Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get the parameterized-type class from a parameterized-type method argument?

Consider this contrived class:

import java.util.List;
public class Test {
    public String chooseRandom(List<String> strings) {
        return null;
    }
}

When using reflection to inspect this method, how can I get the Class object representing java.lang.String (or even the string "java.lang.String") when looking at the arguments for chooseRandom?

I know that Java erases types at compile-time, but they must still be in there, since javap can print them properly. Running javap on this compiled class results in:

Compiled from "Test.java"
public class Test {
  public Test();
  public java.lang.String chooseRandom(java.util.List<java.lang.String>);
}

The parameterized type for java.util.List (java.lang.String) is definitely available... I just can't find out what it is.

I've tried this:

Class clazz = [grab the type of chooseRandom's parameter list's first argument];
String typeName = clazz.getName();
TypeVariable[] genericTypes = clazz.getTypeParameters();
if(null != genericTypes && 0 < genericTypes.length)
{
    boolean first = true;
    typeName += "<";
    for(TypeVariable type : genericTypes)
    {
        if(first) first = false;
        else typeName += ",";

        typeName += type.getTypeName();
    }

    typeName = typeName + ">";
}

This gives me a typeName of java.util.List<E>. What I'm hoping for is java.util.List<java.lang.String>.

I've read a few other questions and answers on SO and none of them really seem to answer this question, or if they do, there is no working code associated with them and the explanations are ... thin.

like image 907
Christopher Schultz Avatar asked Feb 05 '15 21:02

Christopher Schultz


1 Answers

Use the getGenericParameterTypes and getActualTypeArguments methods:

Method m = Test.class.getMethod("chooseRandom", List.class);
Type t = m.getGenericParameterTypes()[0];
// we know, in this case, that t is a ParameterizedType
ParameterizedType p = (ParameterizedType) t;
Type s = p.getActualTypeArguments()[0]; // class java.lang.String

In practice, if you didn't know that there was at least one parameter and it was generic and had one type argument, of course, you would have to add some checks.

like image 132
David Conrad Avatar answered Oct 16 '22 02:10

David Conrad