762

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?

Michael
  • 34,340
  • 9
  • 58
  • 100
robinmag
  • 15,600
  • 18
  • 51
  • 54
  • 2
    Try answers in this question.I think its similar. http://stackoverflow.com/questions/1942644/get-generic-type-of-java-util-list/1942680#1942680 – Emil Aug 09 '10 at 07:37
  • 3
    possible duplicate of [Get generic type of class at runtime](http://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime) – 7hi4g0 Apr 01 '14 at 14:06
  • 1
    possible duplicate of [Instantiating a generic class in Java](http://stackoverflow.com/questions/1090458/instantiating-a-generic-class-in-java) – matiasg Oct 14 '14 at 17:12
  • 1
    `import com.fasterxml.jackson.core.type.TypeReference; ` `new TypeReference(){}` – helloWorld Feb 06 '19 at 11:59

22 Answers22

618

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
    }
}
Zsolt Török
  • 9,493
  • 2
  • 23
  • 24
  • 79
    This answer does provide a valid solution but it is inaccurate to say there is no way to find the generic type at runtime. It turns out type erasure is far more complex than a blanket erasure. My answer shows you how to get the classes generic type. – Ben Thurley Nov 22 '12 at 10:58
  • 4
    @BenThurley Neat trick, but as far as I can see it only works if there is a generic supertype for it to use. In my example, you can't retrieve the type of T in Foo. – Zsolt Török Jun 10 '13 at 09:54
  • @webjockey No, you shouldn't. Assigning the `typeParameterClass` without a default assignment in the constructor is perfectly fine. There's no need to set it a second time. – Adowrath Aug 25 '17 at 07:03
  • This is the first solution that comes to mind, but at times it is not you who will be creating/initiating objects. So you will not be able to use constructor. For e.g. while retrieving JPA entities from database. – Paramvir Singh Karwal Aug 30 '19 at 12:03
  • @ZsoltTörök I think I found the solution to this problem. Please check my answer: https://stackoverflow.com/a/64504193/9432967 – Omid.N Oct 23 '20 at 16:51
259

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 ";
    }
Ben Thurley
  • 6,088
  • 4
  • 30
  • 52
  • 1
    please clarify meaning of **resolveTypeArgument** arguments – gstackoverflow Dec 14 '15 at 16:21
  • getClass() is a method of java.lang.Object which will return the class of the specific object at runtime, this is the object you want to resolve the type for. AbstractHibernateDao.class is just the name of the base class or superclass of the generic type class hierarchy. The import statement is included so you should be able to easily find the docs and check yourself. This is the page https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/GenericTypeResolver.html#resolveTypeArgument-java.lang.Class-java.lang.Class- – Ben Thurley Dec 14 '15 at 16:30
  • What is the spring solution with **version 4.3.6** and higher. It doesn't work with spring 4.3.6. – Erlan Mar 03 '17 at 07:20
  • @Erlan are you sure? I just checked the docs and this class is still present and the methods here haven't been deprecated. – Ben Thurley Jun 22 '17 at 11:20
  • 1
    The link in "Pure Java solution" is broken, it is now http://blog.xebia.com/acessing-generic-types-at-runtime-in-java/ – Nick Breen Sep 26 '17 at 21:33
  • How does `genericType` get initialized? – AlikElzin-kilaka Sep 05 '18 at 06:47
  • 1
    @AlikElzin-kilaka it gets initialised in the constructor using the Spring class GenericTypeResolver. – Ben Thurley Sep 05 '18 at 11:24
  • The "Pure Java solution" link is broken again, is there an updated link? – Chris Nov 26 '19 at 00:27
  • Actually the link still works fine but I've added the code snippet from the blog article anyway. If you want to see the context for that snippet then follow the link. – Ben Thurley Nov 26 '19 at 14:40
  • 4
    java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType – Khan May 06 '20 at 15:46
109

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 );
    }
}
bert bruynooghe
  • 2,761
  • 1
  • 18
  • 18
  • 5
    This is easily the best answer on here! Also, for what it's worth, this is the strategy that Google Guice uses for binding classes with `TypeLiteral` – ATG Jun 05 '14 at 23:44
  • 14
    Note that every time this method of object construction is used, a new anonymous class is created. In other words, two objects `a` and `b` created this way will both extend the same class but not have identical instance classes. `a.getClass() != b.getClass()` – Martin Serrano Mar 20 '15 at 17:04
  • 3
    There is one scenario in which this doesn't work. If Foo should implement an interface, such as Serializable, than the anonymous class would not be Serializable unless the class instantiating is. I tried to workaround it by creating a serializable factory class that creates the anonymous class derived from Foo, but then, for some reason, getActualTypeArguments returns the generic type instead of the actual class. For example: __(new FooFactory()).createFoo()__ – Lior Chaga May 07 '15 at 09:25
40

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();
    }
 }
Paul Whelan
  • 15,841
  • 12
  • 46
  • 79
Andreas Dolk
  • 108,221
  • 16
  • 168
  • 253
22

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.

droidpl
  • 5,632
  • 3
  • 32
  • 46
19

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

  1. Has to be extended with typed class (Child extends Generic<Integer>)

OR

  1. Has to be created as anonymous implementation (new Generic<Integer>() {};)
Lino
  • 17,873
  • 4
  • 40
  • 57
Yaroslav Kovbas
  • 360
  • 3
  • 6
11

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;
    }
}
Octavia Togami
  • 3,638
  • 4
  • 29
  • 42
user1154664
  • 1,362
  • 13
  • 11
10

You can't do it because of type erasure. See also Stack Overflow question Java generics - type erasure - when and what happens.

Community
  • 1
  • 1
Konrad Garus
  • 50,165
  • 42
  • 145
  • 220
9

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>());
Ricky Clarkson
  • 2,821
  • 1
  • 17
  • 20
  • @ Ricky Clarkson: I don't see how this factory should return parametrized foos. Could you please explain how you get Foo out of this? It seems to me this gives only unparametrized Foo. Isn't the T in make10 simply Foo here? – ib84 Mar 13 '13 at 09:03
  • @ib84 I've fixed the code; I seem to have missed that Foo was parameterised when I wrote the answer originally. – Ricky Clarkson Mar 14 '13 at 13:04
6

I have an (ugly but effective) solution for this problem, which does NOT require external dependencies/libraries:

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 __() {
    }
}
unknown6656
  • 2,199
  • 2
  • 26
  • 40
5

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.

Umpa
  • 329
  • 10
  • 15
Peter Tseng
  • 11,991
  • 3
  • 64
  • 53
4

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!

Pontios
  • 1,925
  • 21
  • 26
3

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];
    }
}
Juan Urrego
  • 273
  • 2
  • 8
2

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();
Riaan Schutte
  • 430
  • 1
  • 4
  • 12
2

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() );
    }
Gana
  • 494
  • 3
  • 10
  • 28
1
   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
        }
   }
Abel ANEIROS
  • 4,840
  • 1
  • 21
  • 19
1

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> {
}
Anil Agrawal
  • 1,804
  • 1
  • 19
  • 28
1

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() );
    }
}
Omid.N
  • 796
  • 6
  • 16
0

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>
    }
}
Vahe Gharibyan
  • 2,725
  • 1
  • 21
  • 30
0

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);
Madhu Tomy
  • 262
  • 3
  • 12
0

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;
in my class, and I check if the class type is "Locality" by
if (items.get(0) instanceof Locality) ...

Of course, this only works if the total number of possible classes is limited.

Christine
  • 5,441
  • 4
  • 37
  • 59
-4

I'm using workaround for this:

class MyClass extends Foo<T> {
....
}

MyClass myClassInstance = MyClass.class.newInstance();
nikolai.serdiuk
  • 602
  • 8
  • 11