Type arguments don't get to the runtime, so the calling code must pass a token to construct the Class<T>
object at runtime. I name it token because there are many different objects you can pass to rebuild a Class<T>
object at runtime, for example:
- a
String
, to be used with Class.forName(name)
- a
Class<T>
object
- a type token, ie a subclass of a parameterized type whose arguments are neither type variables nor wildcard (bounded or not), for example a
new List<String>(){}
(I used new
and the curly braces to underline that this expression returns an instance of an anonymous subclass)
With type tokens:
public class MyGenericDAO<T> {
@SuppressWarnings("unchecked")
public Class<T> getTypeParameter() throws Exception {
Type type = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
return (Class<T>) type;
}
}
Note that there is an unchecked conversion when you cast the Type
to a Class<T>
. The calling code then looks like:
MyGenericDAO<Foo> dao = new MyGenericDAO<Foo>(){};
// Then if you want an instance
Foo foo = dao.getTypeParameter().newInstance();
Again, note the curly braces, since super type tokens only work when there is a real class generated at compile time. This approach only works if the client code honors the contract and uses an anonymous inner class every time a DAO object is needed (otherwise the magic of getTypeParameter()
vanishes)