Get generic type of class at runtime

JavaGenericsReflection

Java Problem Overview


How can I achieve this?

public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}

Everything I have tried so far always returns type Object rather than the specific type used.

Java Solutions


Solution 1 - Java

As others mentioned, it's only possible via reflection in certain circumstances.

If you really need the type, this is the usual (type-safe) workaround pattern:

public class GenericClass<T> {
     
     private final Class<T> type;

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

     public Class<T> getMyType() {
         return this.type;
     }
}

Solution 2 - Java

I have seen something like this

private Class<T> persistentClass;

public Constructor() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
 }

in the hibernate GenericDataAccessObjects Example

Solution 3 - Java

Generics are not reified at run-time. This means the information is not present at run-time.

Adding generics to Java while mantaining backward compatibility was a tour-de-force (you can see the seminal paper about it: Making the future safe for the past: adding genericity to the Java programming language).

There is a rich literature on the subject, and some people are dissatisfied with the current state, some says that actually it's a lure and there is no real need for it. You can read both links, I found them quite interesting.

Solution 4 - Java

Use Guava.

import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;

public abstract class GenericClass<T> {
  private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
  private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>

  public Type getType() {
    return type;
  }

  public static void main(String[] args) {
    GenericClass<String> example = new GenericClass<String>() { };
    System.out.println(example.getType()); // => class java.lang.String
  }
}

A while back, I posted some full-fledge examples including abstract classes and subclasses here.

Note: this requires that you instantiate a subclass of GenericClass so it can bind the type parameter correctly. Otherwise it'll just return the type as T.

Solution 5 - Java

Java generics are mostly compile time, this means that the type information is lost at runtime.

class GenericCls<T>
{
    T t;
}

will be compiled to something like

class GenericCls
{
   Object o;
}

To get the type information at runtime you have to add it as an argument of the ctor.

class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}

Example:

GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;

Solution 6 - Java

Sure, you can.

Java does not use the information at run time, for backwards compatibility reasons. But the information is actually present as metadata and can be accessed via reflection (but it is still not used for type-checking).

From the official API:

http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29

However, for your scenario I would not use reflection. I'm personally more inclined to use that for framework code. In your case I would just add the type as a constructor param.

Solution 7 - Java

public abstract class AbstractDao<T>
{
	private final Class<T> persistentClass;
	
	public AbstractDao()
	{
		this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
		        .getActualTypeArguments()[0];
	}
}

Solution 8 - Java

I used follow approach:

public class A<T> {

    protected Class<T> clazz;

	public A() {
  		this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

    public Class<T> getClazz() {
        return clazz;
    }
}

public class B extends A<C> {
   /* ... */
    public void anything() {
       // here I may use getClazz();
    }
}

Solution 9 - Java

I dont think you can, Java uses type erasure when compiling so your code is compatible with applications and libraries that were created pre-generics.

From the Oracle Docs:

> Type Erasure > > Generics were introduced to the Java language to provide tighter type > checks at compile time and to support generic programming. To > implement generics, the Java compiler applies type erasure to: > > Replace all type parameters in generic types with their bounds or > Object if the type parameters are unbounded. The produced bytecode, > therefore, contains only ordinary classes, interfaces, and methods. > Insert type casts if necessary to preserve type safety. Generate > bridge methods to preserve polymorphism in extended generic types. > Type erasure ensures that no new classes are created for parameterized > types; consequently, generics incur no runtime overhead.

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

Solution 10 - Java

Technique described in this article by Ian Robertson works for me.

In short quick and dirty example:

 public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
 {
    /**
     * Method returns class implementing EntityInterface which was used in class
     * extending AbstractDAO
     *
     * @return Class<T extends EntityInterface>
     */
    public Class<T> returnedClass()
    {
        return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
    }

    /**
     * Get the underlying class for a type, or null if the type is a variable
     * type.
     *
     * @param type the type
     * @return the underlying class
     */
    public static Class<?> getClass(Type type)
    {
        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            return getClass(((ParameterizedType) type).getRawType());
        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            Class<?> componentClass = getClass(componentType);
            if (componentClass != null) {
                return Array.newInstance(componentClass, 0).getClass();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Get the actual type arguments a child class has used to extend a generic
     * base class.
     *
     * @param baseClass the base class
     * @param childClass the child class
     * @return a list of the raw classes for the actual type arguments.
     */
    public static <T> List<Class<?>> getTypeArguments(
            Class<T> baseClass, Class<? extends T> childClass)
    {
        Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
        Type type = childClass;
        // start walking up the inheritance hierarchy until we hit baseClass
        while (!getClass(type).equals(baseClass)) {
            if (type instanceof Class) {
                // there is no useful information for us in raw types, so just keep going.
                type = ((Class) type).getGenericSuperclass();
            } else {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Class<?> rawType = (Class) parameterizedType.getRawType();

                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
                }

                if (!rawType.equals(baseClass)) {
                    type = rawType.getGenericSuperclass();
                }
            }
        }

        // finally, for each actual type argument provided to baseClass, determine (if possible)
        // the raw class for that type argument.
        Type[] actualTypeArguments;
        if (type instanceof Class) {
            actualTypeArguments = ((Class) type).getTypeParameters();
        } else {
            actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
        }
        List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
        // resolve types by chasing down type variables.
        for (Type baseType : actualTypeArguments) {
            while (resolvedTypes.containsKey(baseType)) {
                baseType = resolvedTypes.get(baseType);
            }
            typeArgumentsAsClasses.add(getClass(baseType));
        }
        return typeArgumentsAsClasses;
    }
  }

Solution 11 - Java

I think there is another elegant solution.

What you want to do is (safely) "pass" the type of the generic type parameter up from the concerete class to the superclass.

If you allow yourself to think of the class type as "metadata" on the class, that suggests the Java method for encoding metadata in at runtime: annotations.

First define a custom annotation along these lines:

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityAnnotation {
    Class entityClass();
}

You can then have to add the annotation to your subclass.

@EntityAnnotation(entityClass =  PassedGenericType.class)
public class Subclass<PassedGenericType> {...}

Then you can use this code to get the class type in your base class:

import org.springframework.core.annotation.AnnotationUtils;
.
.
.

private Class getGenericParameterType() {
    final Class aClass = this.getClass();
    EntityAnnotation ne = 
         AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);

    return ne.entityClass();
}

Some limitations of this approach are:

  1. You specify the generic type (PassedGenericType) in TWO places rather than one which is non-DRY.

  2. This is only possible if you can modify the concrete subclasses.

Solution 12 - Java

This is my solution:

import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class GenericClass<T extends String> {

  public static void main(String[] args) {
     for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
      System.out.println(typeParam.getName());
      for (Type bound : typeParam.getBounds()) {
         System.out.println(bound);
      }
    }
  }
}

Solution 13 - Java

Here's one way, which I've had to use once or twice:

public abstract class GenericClass<T>{
    public abstract Class<T> getMyType();
}

Along with

public class SpecificClass extends GenericClass<String>{

    @Override
    public Class<String> getMyType(){
        return String.class;
    }
}

Solution 14 - Java

You can't. If you add a member variable of type T to the class (you don't even have to initialise it), you could use that to recover the type.

Solution 15 - Java

Here is 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

2. Has to be created as anonymous implementation (new Generic<Integer>() {};)

Solution 16 - Java

One simple solution for this cab be like below

public class GenericDemo<T>{
	private T type;
	
	GenericDemo(T t)
	{
		this.type = t;
	}
	
	public String getType()
	{
		return this.type.getClass().getName();
	}
	
	public static void main(String[] args)
	{
		GenericDemo<Integer> obj = new  GenericDemo<Integer>(5);
		System.out.println("Type: "+ obj.getType());
	}
}

Solution 17 - Java

To complete some of the answers here, I had to get the ParametrizedType of MyGenericClass, no matter how high is the hierarchy, with the help of recursion:

private Class<T> getGenericTypeClass() {
		return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}

private static ParameterizedType getParametrizedType(Class clazz){
	if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
		return (ParameterizedType) clazz.getGenericSuperclass();
	} else {
		return getParametrizedType(clazz.getSuperclass());
	}
}

Solution 18 - Java

Here is my solution

public class GenericClass<T>
{
    private Class<T> realType;
    
    public GenericClass() {
        findTypeArguments(getClass());
    }
    
    private void findTypeArguments(Type t) {
        if (t instanceof ParameterizedType) {
            Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
            realType = (Class<T>) typeArgs[0];
        } else {
            Class c = (Class) t;
            findTypeArguments(c.getGenericSuperclass());
        }
    }

    public Type getMyType()
    {
        // How do I return the type of T? (your question)
        return realType;
    }
}

No matter how many level does your class hierarchy has, this solution still works, for example:

public class FirstLevelChild<T> extends GenericClass<T> {

}

public class SecondLevelChild extends FirstLevelChild<String> {

}

In this case, getMyType() = java.lang.String

Solution 19 - Java

Here is my trick:

public class Main {

    public static void main(String[] args) throws Exception {

        System.out.println(Main.<String> getClazz());

    }

    static <T> Class getClazz(T... param) {

        return param.getClass().getComponentType();
    }

}

Solution 20 - Java

Here is my solution. The examples should explain it. The only requirement is that a subclass must set the generic type, not an object.

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

public class TypeUtils {

	/*** EXAMPLES ***/

	public static class Class1<A, B, C> {

		public A someA;
		public B someB;
		public C someC;

		public Class<?> getAType() {
			return getTypeParameterType(this.getClass(), Class1.class, 0);
		}

		public Class<?> getCType() {
			return getTypeParameterType(this.getClass(), Class1.class, 2);
		}
	}

	public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {

		public B someB;
		public D someD;
		public E someE;
	}

	public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {

		public E someE;
	}

	public static class Class4 extends Class3<Boolean, Long> {

	}

	public static void test() throws NoSuchFieldException {

		Class4 class4 = new Class4();
		Class<?> typeA = class4.getAType(); // typeA = Integer
		Class<?> typeC = class4.getCType(); // typeC = Long

		Field fieldSomeA = class4.getClass().getField("someA");
		Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer

		Field fieldSomeE = class4.getClass().getField("someE");
		Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean


	}

	/*** UTILS ***/

	public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
		Map<TypeVariable<?>, Type> subMap = new HashMap<>();
		Class<?> superClass;
		while ((superClass = subClass.getSuperclass()) != null) {

			Map<TypeVariable<?>, Type> superMap = new HashMap<>();
			Type superGeneric = subClass.getGenericSuperclass();
			if (superGeneric instanceof ParameterizedType) {

				TypeVariable<?>[] typeParams = superClass.getTypeParameters();
				Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();

				for (int i = 0; i < typeParams.length; i++) {
					Type actualType = actualTypeArgs[i];
					if (actualType instanceof TypeVariable) {
						actualType = subMap.get(actualType);
					}
					if (typeVariable == typeParams[i]) return (Class<?>) actualType;
					superMap.put(typeParams[i], actualType);
				}
			}
			subClass = superClass;
			subMap = superMap;
		}
		return null;
	}

	public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
		return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
	}

	public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
		Class<?> type = null;
		Type genericType = null;

		if (element instanceof Field) {
			type = ((Field) element).getType();
			genericType = ((Field) element).getGenericType();
		} else if (element instanceof Method) {
			type = ((Method) element).getReturnType();
			genericType = ((Method) element).getGenericReturnType();
		}

		if (genericType instanceof TypeVariable) {
			Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
			if (typeVariableType != null) {
				type = typeVariableType;
			}
		}
		
		return type;
	}
	
}

Solution 21 - Java

Just in case you use store a variable using the generic type you can easily solve this problem adding a getClassType method as follows:

public class Constant<T> {
  private T value;
  
  @SuppressWarnings("unchecked")
  public Class<T> getClassType () {
	return ((Class<T>) value.getClass());
  }
}

I use the provided class object later to check if it is an instance of a given class, as follows:

Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
	Constant<Integer> integerConstant = (Constant<Integer>)constant;
	Integer value = integerConstant.getValue();
	// ...
}

Solution 22 - Java

public static final Class<?> getGenericArgument(final Class<?> clazz)
{
	return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}

Solution 23 - Java

If you have a class like:

public class GenericClass<T> {
    private T data;
}

with T variable, then you can print T name:

System.out.println(data.getClass().getSimpleName()); // "String", "Integer", etc.

Solution 24 - Java

If you are working with spring:

public static Class<?>[] resolveTypeArguments(Class<?> parentClass, Class<?> subClass) {
    if (subClass.isSynthetic()) {
        return null;
    }
    return GenericTypeResolver.resolveTypeArguments(subClass, parentClass);
}

By the way, GenericTypeResolver will still get null for the non-subclasses class like the question mentioned, because the generic info of such class was completely erased after compilation.

The only way to solve this question may be:

public class GenericClass<T>
{
    private final Class<T> clazz;
    public Foo(Class<T> clazz) {
        this.clazz= clazz;
    }
    
    public Type getMyType()
    {
        return clazz;
    }
}

Solution 25 - Java

If you cannot change the generic class and use one of the method already explained on this page, then simple approach would be to get the type class based on the runtime instance class name.

Class getType(GenericType runtimeClassMember){
if (ClassA.class.equals(runtimeClassMember.getClass()){
  return TypeForClassA.class;
} else if (ClassB.class.equals(runtimeClassMember.getClass()){
  return TypeForClassB.class;
} 

//throw an expectation or do whatever you want for the cases not described in the if section.
}

Solution 26 - Java

I did the same as @Moesio Above but in Kotlin it could be done this way:

class A<T : SomeClass>() {

    var someClassType : T

    init(){
    this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
    }

}

Solution 27 - Java

This was inspired by Pablo's and CoolMind's answers. Occasionally I have also used the technique from kayz1's answer (expressed in many other answers as well), and I believe it is a decent and reliable way to do what the OP asked.

I chose to define this as an interface (similar to PJWeisberg) first because I have existing types that would benefit from this functionality, particularly a heterogeneous generic union type:

public interface IGenericType<T>
{
    Class<T> getGenericTypeParameterType();
}

Where my simple implementation in a generic anonymous interface implementation looks like the following:

//Passed into the generic value generator function: toStore
//This value name is a field in the enclosing class.
//IUnionTypeValue<T> is a generic interface that extends IGenericType<T>
value = new IUnionTypeValue<T>() {
    ...
    private T storedValue = toStore;
    ...
    
    @SuppressWarnings("unchecked")
    @Override
    public Class<T> getGenericTypeParameterType()
    {
        return (Class<T>) storedValue.getClass();
    }
}

I imagine this could be also implemented by being built with a class definition object as the source, that's just a separate use-case. I think the key is as many other answers have stated, in one way or another, you need to get the type information at runtime to have it available at runtime; the objects themselves maintain their type, but erasure (also as others have said, with appropriate references) causes any enclosing/container types to lose that type information.

Solution 28 - Java

It might be useful to someone. You can Use java.lang.ref.WeakReference; this way:

class SomeClass<N>{
  WeakReference<N> variableToGetTypeFrom;
  
  N getType(){
    return variableToGetTypeFrom.get();
  }
}

Solution 29 - Java

I found this to be a simple understandable and easily explainable solution

public class GenericClass<T> {

    private Class classForT(T...t) {
	    return t.getClass().getComponentType();
    }

    public static void main(String[] args) {
	    GenericClass<String> g = new GenericClass<String>();
	
	    System.out.println(g.classForT());
	    System.out.println(String.class);
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGlennView Question on Stackoverflow
Solution 1 - JavaHenningView Answer on Stackoverflow
Solution 2 - JavaFrVaBeView Answer on Stackoverflow
Solution 3 - JavaewernliView Answer on Stackoverflow
Solution 4 - JavaCody A. RayView Answer on Stackoverflow
Solution 5 - JavajosefxView Answer on Stackoverflow
Solution 6 - JavaJoeri HendrickxView Answer on Stackoverflow
Solution 7 - JavaAli YeganehView Answer on Stackoverflow
Solution 8 - JavaMoesioView Answer on Stackoverflow
Solution 9 - JavaDimitarView Answer on Stackoverflow
Solution 10 - JavaOndrej BozekView Answer on Stackoverflow
Solution 11 - JavaDaBlickView Answer on Stackoverflow
Solution 12 - JavaMatthias MView Answer on Stackoverflow
Solution 13 - JavaPJWeisbergView Answer on Stackoverflow
Solution 14 - JavaandrewmuView Answer on Stackoverflow
Solution 15 - JavaYaroslav KovbasView Answer on Stackoverflow
Solution 16 - JavaPaul92View Answer on Stackoverflow
Solution 17 - JavagalexView Answer on Stackoverflow
Solution 18 - JavaLin Yu ChengView Answer on Stackoverflow
Solution 19 - JavaHRgigerView Answer on Stackoverflow
Solution 20 - JavaPetermaxXView Answer on Stackoverflow
Solution 21 - JavaPablo TrinidadView Answer on Stackoverflow
Solution 22 - Javakayz1View Answer on Stackoverflow
Solution 23 - JavaCoolMindView Answer on Stackoverflow
Solution 24 - JavascruelView Answer on Stackoverflow
Solution 25 - JavaShtefanView Answer on Stackoverflow
Solution 26 - JavaBonestackView Answer on Stackoverflow
Solution 27 - Javajhyry-gcpudView Answer on Stackoverflow
Solution 28 - JavaTheLetchView Answer on Stackoverflow
Solution 29 - JavaMark KarchnerView Answer on Stackoverflow