Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get type of a generic parameter in Java with reflection

People also ask

How do you find the type of generic type?

Use the IsGenericType property to determine whether the type is generic, and use the IsGenericTypeDefinition property to determine whether the type is a generic type definition. Get an array that contains the generic type arguments, using the GetGenericArguments method.

How do you indicate that a class has a generic type parameter?

A generic type is declared by specifying a type parameter in an angle brackets after a type name, e.g. TypeName<T> where T is a type parameter.

Do generics use reflection?

Because the Common Language Runtime (CLR) has access to generic type information at run time, you can use reflection to obtain information about generic types in the same way as for non-generic types.

What is a generic type parameter in Java?

A type parameter, also known as a type variable, is an identifier that specifies a generic type name. The type parameters can be used to declare the return type and act as placeholders for the types of the arguments passed to the generic method, which are known as actual type arguments.


One construct, I once stumbled upon looked like

Class<T> persistentClass = (Class<T>)
   ((ParameterizedType)getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];

So there seems to be some reflection-magic around that I unfortunetly don't fully understand... Sorry.


I want to try to break down the answer from @DerMike to explain:

First, type erasure does not mean that the JDK eliminates type information at runtime. It's a method for allowing compile-time type checking and runtime type compatibility to coexist in the same language. As this block of code implies, the JDK retains the erased type information--it's just not associated with checked casts and stuff.

Second, this provides generic type information to a generic class exactly one level up the heirarchy from the concrete type being checked--i.e. an abstract parent class with generic type parameters can find the concrete types corresponding to its type parameters for a concrete implementation of itself that directly inherits from it. If this class were non-abstract and instantiated, or the concrete implementation were two levels down, this wouldn't work (although a little bit of jimmying could make it apply to any predetermined number of levels beyond one, or up to the lowest class with X generic type parameters, et cetera).

Anyway, on to the explanation. Here's the code again, separated into lines for ease of reference:

1# Class genericParameter0OfThisClass = 
2#     (Class)
3#         ((ParameterizedType)
4#             getClass()
5#                .getGenericSuperclass())
6#                    .getActualTypeArguments()[0];

Let 'us' be the abstract class with generic types that contains this code. Reading this roughly inside out:

  • Line 4 gets the current concrete class' Class instance. This identifies our immediate descendant's concrete type.
  • Line 5 gets that class' supertype as a Type; this is us. Since we're a parametric type we can safely cast ourselves to ParameterizedType (line 3). The key is that when Java determines this Type object, it uses type information present in the child to associate type information with our type parameters in the new ParameterizedType instance. So now we can access concrete types for our generics.
  • Line 6 gets the array of types mapped into our generics, in order as declared in the class code. For this example we pull out the first parameter. This comes back as a Type.
  • Line 2 casts the final Type returned to a Class. This is safe because we know what types our generic type parameters are able to take and can confirm that they will all be classes (I'm not sure how in Java one would go about getting a generic parameter that doesn't have a Class instance associated with it, actually).

...and that's pretty much it. So we push type info from our own concrete implementation back into ourselves, and use it to access a class handle. we could double up getGenericSuperclass() and go two levels, or eliminate getGenericSuperclass() and get values for ourselves as a concrete type (caveat: I haven't tested these scenarios, they haven't come up for me yet).

It gets tricky if your concrete children are be an arbitrary number of hops away, or if you're concrete and not final, and especially tricky if you expect any of your (variably deep) children to have their own generics. But you can usually design around those considerations, so this gets you most of the way.

Hope this helped someone! I recognize this post is ancient. I'll probably snip this explanation and keep it for other questions.


Actually I got this to work. Consider the following snippet:

Method m;
Type[] genericParameterTypes = m.getGenericParameterTypes();
for (int i = 0; i < genericParameterTypes.length; i++) {
     if( genericParameterTypes[i] instanceof ParameterizedType ) {
                Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments();
//parameters[0] contains java.lang.String for method like "method(List<String> value)"

     }
 }

I'm using jdk 1.6


There is a solution actually, by applying the "anonymous class" trick and the ideas from the Super Type Tokens:

public final class Voodoo {
    public static void chill(final List<?> aListWithSomeType) {
        // Here I'd like to get the Class-Object 'SpiderMan'
        System.out.println(aListWithSomeType.getClass().getGenericSuperclass());
        System.out.println(((ParameterizedType) aListWithSomeType
            .getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0]);
    }
    public static void main(String... args) {
        chill(new ArrayList<SpiderMan>() {});
    }
}
class SpiderMan {
}

The trick lies in the creation of an anonymous class, new ArrayList<SpiderMan>() {}, in the place of the original (simple) new ArrayList<SpiderMan>(). The use of an anoymous class (if possible) ensures that the compiler retains information about the type argument SpiderMan given to the type parameter List<?>. Voilà !