How do I get a class instance of generic type T?

I have a generics class, Foo<T>. In a method of Foo, I want to get the class instance of type T, but I just can't call T.class.

What is the preferred way to get around it using T.class?


Solution 1:

The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. I suggest reading the chapter about type erasure in the Java Tutorial for more details.

A popular solution to this is to pass the Class of the type parameter into the constructor of the generic type, e.g.

class Foo<T> {
    final Class<T> typeParameterClass;

    public Foo(Class<T> typeParameterClass) {
        this.typeParameterClass = typeParameterClass;
    }

    public void bar() {
        // you can access the typeParameterClass here and do whatever you like
    }
}

Solution 2:

I was looking for a way to do this myself without adding an extra dependency to the classpath. After some investigation I found that it is possible as long as you have a generic supertype. This was OK for me as I was working with a DAO layer with a generic layer supertype. If this fits your scenario then it's the neatest approach IMHO.

Most generics use cases I've come across have some kind of generic supertype e.g. List<T> for ArrayList<T> or GenericDAO<T> for DAO<T>, etc.

Pure Java solution

The article Accessing generic types at runtime in Java explains how you can do it using pure Java.

@SuppressWarnings("unchecked")
public GenericJpaDao() {
  this.entityBeanType = ((Class) ((ParameterizedType) getClass()
      .getGenericSuperclass()).getActualTypeArguments()[0]);
}

Spring solution

My project was using Spring which is even better as Spring has a handy utility method for finding the type. This is the best approach for me as it looks neatest. I guess if you weren't using Spring you could write your own utility method.

import org.springframework.core.GenericTypeResolver;

public abstract class AbstractHibernateDao<T extends DomainObject> implements DataAccessObject<T>
{

    @Autowired
    private SessionFactory sessionFactory;

    private final Class<T> genericType;

    private final String RECORD_COUNT_HQL;
    private final String FIND_ALL_HQL;

    @SuppressWarnings("unchecked")
    public AbstractHibernateDao()
    {
        this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractHibernateDao.class);
        this.RECORD_COUNT_HQL = "select count(*) from " + this.genericType.getName();
        this.FIND_ALL_HQL = "from " + this.genericType.getName() + " t ";
    }

Full code example

Some people are struggling in the comments to get this working so I wrote a small application to show both approaches in action. https://github.com/benthurley82/generic-type-resolver-test

Solution 3:

There is a small loophole however: if you define your Foo class as abstract. That would mean you have to instantiate you class as:

Foo<MyType> myFoo = new Foo<MyType>(){};

(Note the double braces at the end.)

Now you can retrieve the type of T at runtime:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];

Note however that mySuperclass has to be the superclass of the class definition actually defining the final type for T.

It is also not very elegant, but you have to decide whether you prefer new Foo<MyType>(){} or new Foo<MyType>(MyType.class); in your code.


For example:

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.NoSuchElementException;

/**
 * Captures and silently ignores stack exceptions upon popping.
 */
public abstract class SilentStack<E> extends ArrayDeque<E> {
  public E pop() {
    try {
      return super.pop();
    }
    catch( NoSuchElementException nsee ) {
      return create();
    }
  }

  public E create() {
    try {
      Type sooper = getClass().getGenericSuperclass();
      Type t = ((ParameterizedType)sooper).getActualTypeArguments()[ 0 ];

      return (E)(Class.forName( t.toString() ).newInstance());
    }
    catch( Exception e ) {
      return null;
    }
  }
}

Then:

public class Main {
    // Note the braces...
    private Deque<String> stack = new SilentStack<String>(){};

    public static void main( String args[] ) {
      // Returns a new instance of String.
      String s = stack.pop();
      System.out.printf( "s = '%s'\n", s );
    }
}

Solution 4:

A standard approach/workaround/solution is to add a class object to the constructor(s), like:

 public class Foo<T> {

    private Class<T> type;
    public Foo(Class<T> type) {
      this.type = type;
    }

    public Class<T> getType() {
      return type;
    }

    public T newInstance() {
      return type.newInstance();
    }
 }

Solution 5:

Imagine you have an abstract superclass that is generic:

public abstract class Foo<? extends T> {}

And then you have a second class that extends Foo with a generic Bar that extends T:

public class Second extends Foo<Bar> {}

You can get the class Bar.class in the Foo class by selecting the Type (from bert bruynooghe answer) and infering it using Class instance:

Type mySuperclass = myFoo.getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
//Parse it as String
String className = tType.toString().split(" ")[1];
Class clazz = Class.forName(className);

You have to note this operation is not ideal, so it is a good idea to cache the computed value to avoid multiple calculations on this. One of the typical uses is in generic DAO implementation.

The final implementation:

public abstract class Foo<T> {

    private Class<T> inferedClass;

    public Class<T> getGenericClass(){
        if(inferedClass == null){
            Type mySuperclass = getClass().getGenericSuperclass();
            Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
            String className = tType.toString().split(" ")[1];
            inferedClass = Class.forName(className);
        }
        return inferedClass;
    }
}

The value returned is Bar.class when invoked from Foo class in other function or from Bar class.