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
?
import com.fasterxml.jackson.core.type.TypeReference;
new TypeReference<T>(){}
new TypeReference<Foo<Bar>>() {}
as a parameter to my deserialized model reader method.
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 ";
}
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
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 );
}
}
TypeLiteral
a
and b
created this way will both extend the same class but not have identical instance classes. a.getClass() != b.getClass()
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();
}
}
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.
toString().split(" ")[1]
that was the problem, avoid the "class "
Here is a working solution:
@SuppressWarnings("unchecked")
private Class<T> getGenericTypeClass() {
try {
String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
return (Class<T>) clazz;
} catch (Exception e) {
throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
}
}
NOTES: Can be used only as superclass
Has to be extended with typed class (Child extends Generic
OR
Has to be created as anonymous implementation (new Generic
I had this problem in an abstract generic class. In this particular case, the solution is simpler:
abstract class Foo<T> {
abstract Class<T> getTClass();
//...
}
and later on the derived class:
class Bar extends Foo<Whatever> {
@Override
Class<T> getTClass() {
return Whatever.class;
}
}
You can't do it because of type erasure. See also Stack Overflow question Java generics - type erasure - when and what happens.
Contrary to most answers, it is possible (WITHOUT external libraries!)
The following is my (ugly, yet effective) solution for this problem:
import java.lang.reflect.TypeVariable;
public static <T> Class<T> getGenericClass() {
__<T> instance = new __<T>();
TypeVariable<?>[] parameters = instance.getClass().getTypeParameters();
return (Class<T>)parameters[0].getClass();
}
// Generic helper class which (only) provides type information. This avoids
// the usage of a local variable of type T, which would have to be initialized.
private final class __<T> {
private __() { }
}
TypeVariableImpl<T>
rather than the class type of T
itself
TypeVariableImpl<T>
seems to be assignable to Class<T>
, doesn't it? At least, I do not get any compiler errors.... I have to admit, that I'm not a java guy though ... so I might be missing some obvious flaw/drawback/consequence.
A better route than the Class the others suggested is to pass in an object that can do what you would have done with the Class, e.g., create a new instance.
interface Factory<T> {
T apply();
}
<T> void List<T> make10(Factory<T> factory) {
List<T> result = new ArrayList<T>();
for (int a = 0; a < 10; a++)
result.add(factory.apply());
return result;
}
class FooFactory<T> implements Factory<Foo<T>> {
public Foo<T> apply() {
return new Foo<T>();
}
}
List<Foo<Integer>> foos = make10(new FooFactory<Integer>());
I assume that, since you have a generic class, you would have a variable like that:
private T t;
(this variable needs to take a value at the constructor)
In that case you can simply create the following method:
Class<T> getClassOfInstance()
{
return (Class<T>) t.getClass();
}
Hope it helps!
It's possible:
class Foo<T> {
Class<T> clazz = (Class<T>) DAOUtil.getTypeArguments(Foo.class, this.getClass()).get(0);
}
You need two functions from hibernate-generic-dao/blob/master/dao/src/main/java/com/googlecode/genericdao/dao/DAOUtil.java.
For more explanations, see Reflecting generics.
I found a generic and simple way to do that. In my class I created a method that returns the generic type according to it's position in the class definition. Let's assume a class definition like this:
public class MyClass<A, B, C> {
}
Now let's create some attributes to persist the types:
public class MyClass<A, B, C> {
private Class<A> aType;
private Class<B> bType;
private Class<C> cType;
// Getters and setters (not necessary if you are going to use them internally)
}
Then you can create a generic method that returns the type based on the index of the generic definition:
/**
* Returns a {@link Type} object to identify generic types
* @return type
*/
private Type getGenericClassType(int index) {
// To make it use generics without supplying the class type
Type type = getClass().getGenericSuperclass();
while (!(type instanceof ParameterizedType)) {
if (type instanceof ParameterizedType) {
type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
} else {
type = ((Class<?>) type).getGenericSuperclass();
}
}
return ((ParameterizedType) type).getActualTypeArguments()[index];
}
Finally, in the constructor just call the method and send the index for each type. The complete code should look like:
public class MyClass<A, B, C> {
private Class<A> aType;
private Class<B> bType;
private Class<C> cType;
public MyClass() {
this.aType = (Class<A>) getGenericClassType(0);
this.bType = (Class<B>) getGenericClassType(1);
this.cType = (Class<C>) getGenericClassType(2);
}
/**
* Returns a {@link Type} object to identify generic types
* @return type
*/
private Type getGenericClassType(int index) {
Type type = getClass().getGenericSuperclass();
while (!(type instanceof ParameterizedType)) {
if (type instanceof ParameterizedType) {
type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
} else {
type = ((Class<?>) type).getGenericSuperclass();
}
}
return ((ParameterizedType) type).getActualTypeArguments()[index];
}
}
As explained in other answers, to use this ParameterizedType
approach, you need to extend the class, but that seems like extra work to make a whole new class that extends it...
So, making the class abstract it forces you to extend it, thus satisfying the subclassing requirement. (using lombok's @Getter).
@Getter
public abstract class ConfigurationDefinition<T> {
private Class<T> type;
...
public ConfigurationDefinition(...) {
this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
...
}
}
Now to extend it without defining a new class. (Note the {} on the end... extended, but don't overwrite anything - unless you want to).
private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){};
private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){};
...
Class stringType = myConfigA.getType();
Class fileType = myConfigB.getType();
That is pretty straight forward. If you need from within the same class:
Class clazz = this.getClass();
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
try {
Class typeClass = Class.forName( parameterizedType.getActualTypeArguments()[0].getTypeName() );
// You have the instance of type 'T' in typeClass variable
System.out.println( "Class instance name: "+ typeClass.getName() );
} catch (ClassNotFoundException e) {
System.out.println( "ClassNotFound!! Something wrong! "+ e.getMessage() );
}
public <T> T yourMethodSignature(Class<T> type) {
// get some object and check the type match the given type
Object result = ...
if (type.isAssignableFrom(result.getClass())) {
return (T)result;
} else {
// handle the error
}
}
If you are extending or implementing any class/interface that are using generics , you may get the Generic Type of parent class/interface, without modifying any existing class/interface at all.
There could be three possibilities,
Case 1 When your class is extending a class that is using Generics
public class TestGenerics {
public static void main(String[] args) {
Type type = TestMySuperGenericType.class.getGenericSuperclass();
Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
for(Type gType : gTypes){
System.out.println("Generic type:"+gType.toString());
}
}
}
class GenericClass<T> {
public void print(T obj){};
}
class TestMySuperGenericType extends GenericClass<Integer> {
}
Case 2 When your class is implementing an interface that is using Generics
public class TestGenerics {
public static void main(String[] args) {
Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
for(Type type : interfaces){
Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
for(Type gType : gTypes){
System.out.println("Generic type:"+gType.toString());
}
}
}
}
interface GenericClass<T> {
public void print(T obj);
}
class TestMySuperGenericType implements GenericClass<Integer> {
public void print(Integer obj){}
}
Case 3 When your interface is extending an interface that is using Generics
public class TestGenerics {
public static void main(String[] args) {
Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
for(Type type : interfaces){
Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
for(Type gType : gTypes){
System.out.println("Generic type:"+gType.toString());
}
}
}
}
interface GenericClass<T> {
public void print(T obj);
}
interface TestMySuperGenericType extends GenericClass<Integer> {
}
Many people don't know this trick! Actually, I just found it today! It works like a dream! Just check this example out:
public static void main(String[] args) {
Date d=new Date(); //Or anything you want!
printMethods(d);
}
public static <T> void printMethods(T t){
Class<T> clazz= (Class<T>) t.getClass(); // There you go!
for ( Method m : clazz.getMethods()){
System.out.println( m.getName() );
}
}
public static void printMethods(Object t)
and it will do exactly the same. There is no “trick” in this answer but just an obsolete type parameter.
getConstructures()
on clazz
to do it. Now the question is why the OP wants to get the T.class
where he can just do t.getClass()
?
getConstructors
on a Class
object. 1) but your code doesn’t 2) but it still doesn’t justify the use of the type parameter. The result of t.getClass()
is Class<? extends Object>
, whether you declare the parameter as T
or Object
. It makes no difference. You have an unchecked type cast (Class<T>)
in your code. That’s not better than using getClass().getConstructor().newInstance()
casting the result to whatever your want.
I've created an example based on one of two most promising solutions here from this question.
The result is however not so promising, at least for my use case.
Only one approach is working, but you need a super class containing the method and the generic has to be set in the child class and cannot be assigned dynamically (which my use case sadly is)
import org.junit.jupiter.api.Test;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class GenericTest {
/**
* only this will work!
*/
@Test
void testGetGenericTypeClassFromChildClassWithSpecifiedType() {
TestClassWithSpecifiedType parent = new TestClassWithSpecifiedType();
assertEquals(SomeGenericType.class, parent.getGenericTypeClass());
}
/**
* won't work!
*/
@Test
void testGetGenericTypeClassFromChildClassWithUnspecifiedType() {
TestClassWithUnspecifiedType<SomeGenericType> parent = new TestClassWithUnspecifiedType<>();
assertThrows(IllegalStateException.class, parent::getGenericTypeClass);
}
/**
* won't work
*/
@Test
void testGetGenericTypeClassWithUnspecifiedType() {
SomeGenericTypedClass<SomeGenericType> parent = new SomeGenericTypedClass<>();
assertThrows(IllegalStateException.class, parent::getGenericTypeClass);
}
/**
* won't work
* returns object instead!
*/
@Test
void testGetLoadedClassFromObject() {
Foo<SomeGenericType> foo = new Foo<>();
Class<?> barClass = foo.getBarClass();
assertEquals(SomeGenericType.class, barClass);
}
/**
* A class that has specified the type parameter
*/
public static class TestClassWithSpecifiedType extends AbstractGenericTypedClass<SomeGenericType> {
}
/**
* A class where the type parameter will be specified on demand
*
* @param <T>
*/
public static class TestClassWithUnspecifiedType<T> extends AbstractGenericTypedClass<T> {
}
/**
* An abstract class, because otherwise finding the parameter will not work
*/
@SuppressWarnings("unchecked")
public static abstract class AbstractGenericTypedClass<T> {
@SuppressWarnings("unchecked")
public Class<T> getGenericTypeClass() {
try {
String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
return (Class<T>) clazz;
} catch (Exception e) {
throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
}
}
}
/**
* A typed class without abstract super class
*
* @param <T>
*/
public static class SomeGenericTypedClass<T> {
@SuppressWarnings("unchecked")
public Class<T> getGenericTypeClass() {
try {
String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
return (Class<T>) clazz;
} catch (Exception e) {
throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
}
}
}
/**
* Some generic type - won't work with primitives such as String, Integer, Double!
*/
public static class SomeGenericType {
}
public static class Foo<T> {
// The class:
private final Class<?> barClass;
public Foo() {
try {
// Im giving it [0] cuz Bar is the first TypeParam
Type[] bounds = getClass().getTypeParameters()[0].getBounds();
// Here, we get the class now:
barClass = Class.forName(bounds[0].getTypeName());
} catch (ClassNotFoundException e) {
// will never happen!
throw new Error("Something impossible happened!", e);
}
}
public Class<?> getBarClass() {
return barClass;
}
}
}
I do not really understand why this has to be so complicated, but I bet there have to be some technical limitations for the dynamically setting of parameters.
Actually, I suppose you have a field in your class of type T. If there's no field of type T, what's the point of having a generic Type? So, you can simply do an instanceof on that field.
In my case, I have a
List<T> items;
if (items.get(0) instanceof Locality) ...
Of course, this only works if the total number of possible classes is limited.
This question is old, but now the best is use google Gson
.
An example to get custom viewModel
.
Class<CustomViewModel<String>> clazz = new GenericClass<CustomViewModel<String>>().getRawType();
CustomViewModel<String> viewModel = viewModelProvider.get(clazz);
Generic type class
class GenericClass<T>(private val rawType: Class<*>) {
constructor():this(`$Gson$Types`.getRawType(object : TypeToken<T>() {}.getType()))
fun getRawType(): Class<T> {
return rawType as Class<T>
}
}
I wanted to pass T.class to a method which make use of Generics
The method readFile reads a .csv file specified by the fileName with fullpath. There can be csv files with different contents hence i need to pass the model file class so that i can get the appropriate objects. Since this is reading csv file i wanted to do in a generic way. For some reason or other none of the above solutions worked for me. I need to use Class<? extends T> type
to make it work. I use opencsv library for parsing the CSV files.
private <T>List<T> readFile(String fileName, Class<? extends T> type) {
List<T> dataList = new ArrayList<T>();
try {
File file = new File(fileName);
Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
Reader headerReader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
CSVReader csvReader = new CSVReader(headerReader);
// create csv bean reader
CsvToBean<T> csvToBean = new CsvToBeanBuilder(reader)
.withType(type)
.withIgnoreLeadingWhiteSpace(true)
.build();
dataList = csvToBean.parse();
}
catch (Exception ex) {
logger.error("Error: ", ex);
}
return dataList;
}
This is how the readFile method is called
List<RigSurfaceCSV> rigSurfaceCSVDataList = readSurfaceFile(surfaceFileName, RigSurfaceCSV.class);
I'm using workaround for this:
class MyClass extends Foo<T> {
....
}
MyClass myClassInstance = MyClass.class.newInstance();
Success story sharing
typeParameterClass
without a default assignment in the constructor is perfectly fine. There's no need to set it a second time.