How do I get a class instance of generic type T?
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 }}
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 "; }
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 ); }}