Get generic type information [duplicate] - java

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.

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;
}
}

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

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.

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.

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;

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.

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

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();
}
}

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

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;
}
}

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:
You specify the generic type (PassedGenericType) in TWO places rather than one which is non-DRY.
This is only possible if you can modify the concrete subclasses.

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;
}
}

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);
}
}
}
}

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>() {};)

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.

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());
}
}

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());
}
}

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

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();
}
}

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();
// ...
}

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;
}
}

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.

Use an abstract method that returns the class type then use it in that class and wherever you extend generic class you will have to implement that abstract method to return the required class type
public class AbsractService<T>{
public abstract Class<T> getClassType ();
.......
}
at runtime
class AnimalService extends AbstractService<Animal>{
#Override
public Class<Animal> getClassType (){
return Animal.class;
}
.....
}

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

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;
}
}

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.
}

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>
}
}

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.

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();
}
}

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);
}
}

Related

Write a single generics method to cover multiple methods for String to Enum value conversion

I created two Java enums,
public enum TypeEnum {
TYPE_A, TYPE_B
}
and
public enum FormatEnum{
FORMAT_X, FORMAT_Y
}
Next, I wrote two functions to convert an incoming String to an enum value:
private TypeEnum convertType(String test) {
return TypeEnum.valueOf(test);
}
private FormatEnum convertFormat(String test) {
return FormatEnum.valueOf(test);
}
Next, I wanted to unify these two conversion methods under a single method with generics. I tried this in two ways:
private <T extends Enum> Enum convertToEnumValue(T localEnum, String value) {
return T.valueOf(localEnum.getClass(), value);
}
and
private static <T extends Enum> T convertToEnumValue(Class<T> enumType, String value) {
return (T) T.valueOf(enumType, value);
}
I couldn't write a call to these methods that would compile.
Is there a way to correct them to make them work?
There is no need to declare your own method, as JDK java.lang.Enum already declares one:
FormatEnum y =Enum.valueOf(FormatEnum.class, "FORMAT_Y");
TypeEnum a = Enum.valueOf(TypeEnum.class, "TYPE_A");
This works because Enum is the base class of all enum types and so when you call TypeEnum.valueOf(s); you are calling Enum.valueOf(s)
…Is there a way to correct them to make them work?…
I got your examples to work with these very small corrections…:
class DeduperAnswer {
private <T extends Enum> T convertToEnumValue(T localEnum, String value) {
return ( T ) T.valueOf(localEnum.getClass(), value);
}
private static <T extends Enum> T convertToEnumValue(Class<T> enumType, String value) {
return ( T ) T.valueOf(enumType, value);
}
static public void main(String ...args){
DeduperAnswer da = new DeduperAnswer();
TypeEnum typB = da.convertToEnumValue(TypeEnum.TYPE_B, "TYPE_B");
FormatEnum fmtX = convertToEnumValue(FormatEnum.FORMAT_X.getClass(), "FORMAT_X");
}
}
Of course, there's more than one way to skin a cat — as the saying goes. But seeing as your solution works for you, you're good to go.
I suspect you are looking for the following method:
public static <E extends Enum<E>> E toMember(Class<E> clazz, String name) {
//TODO input validations;
for (E member : clazz.getEnumConstants()) {
if (member.name().equals(name)) {
return member;
}
}
return null; //Or throw element not found exception
}
//More elegant form of the previous one
public static <E extends Enum<E>> E toMember(Class<E> clazz, String name, E defaultMember) {
//TODO input validations;
for (E member : clazz.getEnumConstants()) {
if (member.name().equals(name)) {
return member;
}
}
return defaultMember;
}
Note the generic E extends Enum<E>

Using a generic type of any nested subclass within its abstract superclass

Suppose you have the following abstract java class:
public abstract class AbstractRequestHandler<I,O> {
I input;
O output;
}
and the following child classes hierarchy:
public abstract class AbstractUserRequestHandler<I extends User,O> extends AbstractRequestHandler<I,O>{...}
public abstract class AbstractUniversityRequestHandler<I extends UniversityUser> extends AbstractUserRequestHandler<I,String>{...}
public class StudentRequestHandler extends AbstractUniversityRequestHandler<Student>{...}
public class TeacherRequestHandler extends AbstractUniversityRequestHandler<Teacher>{...}
Suppose you need to use at a given point on the super class the generic type, for example in order to deserialize on the constructor the request json to the specific request object using gson library as follow:
public AbstractRequestHandler(final String inputJson) {
input = new Gson().fromJson(inputJson,typeOfI);
}
You need the type of generic I within variable "typeOfI"
Is there a global solution that allows to get the generic type specified by a concrete child class that respects the following constraints?
The type is gotten at runtime regardless the child classes hierarchy ( that can be also more complex the one given as example on this question )
The developer just needs to define the generic extending the super class without manually specify the generic type somewhere on concrete child class ( for example on overrided method or constructor )
So that if you want to define a new concrete child that assign a new value to a generic you can just write the following concrete class for example:
public class StudentRequestHandler extends AbstractUniversityRequestHandler<Student>{
public StudentRequestHandler(String inputJson) {
super(inputJson);
}
}
I found the following solutions but they don't respect both the asked solution constraints.
Solution that breaks constraint n°2
A solution could be to define an abstract method on the superclass as follow
protected abstract Type getRequestType();
and then implement it on every concrete child class that defines the generic:
public class StudentRequestHandler extends AbstractUniversityRequestHandler<Student>{
public StudentRequestHandler(String inputJson) {
super(inputJson);
}
#Override
protected Type getRequestType() {
return Student.class;
}
}
Then the getRequestType() method can be used on constructor on the target superclass:
public AbstractRequestHandler(final String inputJson) {
request = new Gson().fromJson(inputJson,getRequestType());
}
But even if it works regardless the child classes hierarchy ( respect constraint n°1 ) the developer should manually implement an abstract method on each concrete child class.
Solution that breaks constraint n°1
If the hierarchy is simple having only a direct child that extend from the target superclass, as for example:
public class TeacherRequestHandler extends AbstractRequestHandler<Teacher,String>{...}
a working solution has been proposed by #naikus ( https://stackoverflow.com/users/306602/naikus ) on the following stackoverflow thread:
Using a generic type of a subclass within it's abstract superclass?
However this doesn't work if the concrete class is not a direct child of the superclass that defines the generics ( as the one proposed as example on this question ).
Edit: after reading your answer and testing many other possible cases I decided to edit your code and re-write it to support all other possible edge cases to include tracking of generics nested deeply inside other generic types.
Sadly to support all cases we need a lot more code than you provided, generics are very tricky, like consider class like this:
private class SomeClass<A, B, C, D, E, F> {}
private class SomeConfusingClass<A> extends SomeClass<List<Void>[], List<? extends A>[], List<? extends A[][][]>[][][], List<? extends String[]>[], Map<List<? extends A[]>, A[][]>[], A> {}
private class TestClass extends SomeConfusingClass<Void> {}
To even start doing this we need to have own implementation of java generic types to later be able to construct types like List<String>[] as there is no way to create such type dynamically with raw java API.
This is pretty popular way of handling generic in libraries like that, you can see similar thing in jackson library and many more.
So we need implementation of GenericArrayType, ParameterizedType and WildcardType:
private static class ResolvedGenericArrayType implements GenericArrayType {
private final Type genericComponentType;
ResolvedGenericArrayType(Type genericComponentType) {
this.genericComponentType = genericComponentType;
}
#Override
public Type getGenericComponentType() {
return genericComponentType;
}
public String toString() {
return getGenericComponentType().toString() + "[]";
}
#Override
public boolean equals(Object o) {
if (o instanceof GenericArrayType) {
GenericArrayType that = (GenericArrayType) o;
return Objects.equals(genericComponentType, that.getGenericComponentType());
} else
return false;
}
#Override
public int hashCode() {
return Objects.hashCode(genericComponentType);
}
}
private static class ResolvedParameterizedType implements ParameterizedType {
private final Type[] actualTypeArguments;
private final Class<?> rawType;
private final Type ownerType;
private ResolvedParameterizedType(Type rawType, Type[] actualTypeArguments, Type ownerType) {
this.actualTypeArguments = actualTypeArguments;
this.rawType = (Class<?>) rawType;
this.ownerType = (ownerType != null) ? ownerType : this.rawType.getDeclaringClass();
}
public Type[] getActualTypeArguments() {
return actualTypeArguments.clone();
}
public Class<?> getRawType() {
return rawType;
}
public Type getOwnerType() {
return ownerType;
}
#Override
public boolean equals(Object o) {
if (!(o instanceof ParameterizedType)) {
return false;
}
ParameterizedType that = (ParameterizedType) o;
if (this == that)
return true;
Type thatOwner = that.getOwnerType();
Type thatRawType = that.getRawType();
return Objects.equals(ownerType, thatOwner) && Objects.equals(rawType, thatRawType) &&
Arrays.equals(actualTypeArguments, that.getActualTypeArguments());
}
#Override
public int hashCode() {
return Arrays.hashCode(actualTypeArguments) ^
Objects.hashCode(ownerType) ^
Objects.hashCode(rawType);
}
public String toString() {
StringBuilder sb = new StringBuilder();
if (ownerType != null) {
sb.append(ownerType.getTypeName());
sb.append("$");
if (ownerType instanceof ResolvedParameterizedType) {
sb.append(rawType.getName().replace(((ResolvedParameterizedType) ownerType).rawType.getName() + "$", ""));
} else
sb.append(rawType.getSimpleName());
} else
sb.append(rawType.getName());
if (actualTypeArguments != null) {
StringJoiner sj = new StringJoiner(", ", "<", ">");
sj.setEmptyValue("");
for (Type t : actualTypeArguments) {
sj.add(t.getTypeName());
}
sb.append(sj.toString());
}
return sb.toString();
}
}
private static class ResolvedWildcardType implements WildcardType {
private final Type[] upperBounds;
private final Type[] lowerBounds;
public ResolvedWildcardType(Type[] upperBounds, Type[] lowerBounds) {
this.upperBounds = upperBounds;
this.lowerBounds = lowerBounds;
}
public Type[] getUpperBounds() {
return upperBounds.clone();
}
public Type[] getLowerBounds() {
return lowerBounds.clone();
}
public String toString() {
Type[] lowerBounds = getLowerBounds();
Type[] bounds = lowerBounds;
StringBuilder sb = new StringBuilder();
if (lowerBounds.length > 0)
sb.append("? super ");
else {
Type[] upperBounds = getUpperBounds();
if (upperBounds.length > 0 && !upperBounds[0].equals(Object.class)) {
bounds = upperBounds;
sb.append("? extends ");
} else
return "?";
}
StringJoiner sj = new StringJoiner(" & ");
for (Type bound : bounds) {
sj.add(bound.getTypeName());
}
sb.append(sj.toString());
return sb.toString();
}
#Override
public boolean equals(Object o) {
if (o instanceof WildcardType) {
WildcardType that = (WildcardType) o;
return Arrays.equals(this.getLowerBounds(), that.getLowerBounds()) && Arrays.equals(this.getUpperBounds(), that.getUpperBounds());
} else
return false;
}
#Override
public int hashCode() {
Type[] lowerBounds = getLowerBounds();
Type[] upperBounds = getUpperBounds();
return Arrays.hashCode(lowerBounds) ^ Arrays.hashCode(upperBounds);
}
}
You can basically copy them from JDK and just do some cleanup.
Next utility we need is a function to validate at the end if we did everything right, like we don't want to return Map<List<? extends X>[]> where X is still not resolved TypeVariable:
private static boolean isDefined(Type type) {
if (type instanceof Class) {
return true;
}
if (type instanceof GenericArrayType) {
return isDefined(((GenericArrayType) type).getGenericComponentType());
}
if (type instanceof WildcardType) {
for (Type lowerBound : ((WildcardType) type).getLowerBounds()) {
if (!isDefined(lowerBound)) {
return false;
}
}
for (Type upperBound : ((WildcardType) type).getUpperBounds()) {
if (!isDefined(upperBound)) {
return false;
}
}
return true;
}
if (!(type instanceof ParameterizedType)) {
return false;
}
for (Type typeArgument : ((ParameterizedType) type).getActualTypeArguments()) {
if (!isDefined(typeArgument)) {
return false;
}
}
return true;
}
Simple recursive function will do this for us. We just check for every possible generic type and check if every member of it is also defined, and unless we will find some hidden TypeVariable we are fine.
Main function can stay the same as in your code, we only will edit that one check at the end to use our new function:
public static Type getParameterizedType(Class<?> klass, Class<?> rootClass, int paramTypeNumber) throws GenericsException {
int targetClassParametersNumber = rootClass.getTypeParameters().length;
if (targetClassParametersNumber == 0) {
throw new GenericsException(String.format("Target class [%s] has no parameters type", rootClass.getName()));
} else if (targetClassParametersNumber - 1 < paramTypeNumber)
throw new GenericsException(String.format("Target class [%s] has parameters type which index start from [0] to [%s]. You requested instead parameter with index [%s]", rootClass, paramTypeNumber - 1, targetClassParametersNumber));
Type type = analyzeParameterizedTypes(klass, klass, rootClass, paramTypeNumber, null);
if (!isDefined(type))
throw new GenericsException(String.format("Parameter [%s] with index [%d] defined on class [%s] has not been valued yet on child class [%s]", type, paramTypeNumber, rootClass.getName(), klass.getName()));
return type;
}
Now lets work on our main
public static Type analyzeParameterizedTypes(final Class<?> klass, final Class<?> targetClass, final Class<?> rootClass, final int paramTypeNumber, Map<Integer, Type> childClassTypes) throws GenericsException {
function, the begging stays the same, we collect all TypeVariable to simple map, keeping already collected information from previous loop on previous class.
Type superclassType = klass.getGenericSuperclass();
Map<TypeVariable<?>, Type> currentClassTypes = new HashMap<>();
int z = 0;
if (childClassTypes != null) {
for (TypeVariable<?> variable : klass.getTypeParameters()) {
currentClassTypes.put(variable, childClassTypes.get(z));
z++;
}
}
Then we have our loop collecting and refining our type arguments:
Map<Integer, Type> superClassesTypes = new HashMap<>();
if (superclassType instanceof ParameterizedType) {
int i = 0;
for (final Type argType : ((ParameterizedType) superclassType).getActualTypeArguments()) {
if (argType instanceof TypeVariable) {
superClassesTypes.put(i, currentClassTypes.containsKey(argType) ? currentClassTypes.get(argType) : argType);
} else {
superClassesTypes.put(i, refineType(klass, argType, currentClassTypesByName));
}
i++;
}
}
There 2 paths for each type argument, if its TypeVariable we just keep tracking it, and if its anything else we try to "refine" it from any possible references to TypeVariable. This is the most complicated process of this code, and this is why we needed all these classes above.
We start from this simple recursive dispatch method that handles all possible types:
private static Type refineType(Type type, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
if (type instanceof Class) {
return type;
}
if (type instanceof GenericArrayType) {
return refineArrayType((GenericArrayType) type, typeVariablesMap);
}
if (type instanceof ParameterizedType) {
return refineParameterizedType((ParameterizedType) type, typeVariablesMap);
}
if (type instanceof WildcardType) {
return refineWildcardType((WildcardType) type, typeVariablesMap);
}
if (type instanceof TypeVariable) {
return typeVariablesMap.get(type);
}
throw new GenericsException("Unsolvable generic type: " + type);
}
And small utility method to run it on array of types:
private static Type[] refineTypes(Type[] types, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
Type[] refinedTypes = new Type[types.length];
for (int i = 0; i < types.length; i++) {
refinedTypes[i] = refineType(types[i], typeVariablesMap);
}
return refinedTypes;
}
Each type goes to own function, or if its TypeVariable we just fetch resolved one from map. Note that this can return null, and I did not handle it here. This could be improved later. For classes we don't need to do anything so we can just return class itself.
For GenericArrayType we need to first find out how many dimension such array might have (this could be handled by recursion in our refine method too, but then its a bit harder to debug in my opinion):
private static int getArrayDimensions(GenericArrayType genericArrayType) {
int levels = 1;
GenericArrayType currentArrayLevel = genericArrayType;
while (currentArrayLevel.getGenericComponentType() instanceof GenericArrayType) {
currentArrayLevel = (GenericArrayType) currentArrayLevel.getGenericComponentType();
levels += 1;
}
return levels;
}
Then we want to extract that nested component type of array, so for List<A>[][][] we want just List<A>:
private static Type getArrayNestedComponentType(GenericArrayType genericArrayType) {
GenericArrayType currentArrayLevel = genericArrayType;
while (currentArrayLevel.getGenericComponentType() instanceof GenericArrayType) {
currentArrayLevel = (GenericArrayType) currentArrayLevel.getGenericComponentType();
}
return currentArrayLevel.getGenericComponentType();
}
And then we need to refine this type, so our List<A> will change to eg List<String>:
Type arrayComponentType = refineType(getArrayNestedComponentType(genericArrayType), typeVariablesMap);
And rebuild our generic structure using refined type, so our created List<String> will change back to List<String>[][][]:
private static Type buildArrayType(Type componentType, int levels) throws GenericsException {
if (componentType instanceof Class) {
return Array.newInstance(((Class<?>) componentType), new int[levels]).getClass();
} else if (componentType instanceof ParameterizedType) {
GenericArrayType genericArrayType = new ResolvedGenericArrayType(componentType);
for (int i = 1; i < levels; i++) {
genericArrayType = new ResolvedGenericArrayType(genericArrayType);
}
return genericArrayType;
} else {
throw new GenericsException("Array can't be of generic type");
}
}
And whole function looks like this:
private static Type refineArrayType( GenericArrayType genericArrayType, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
int levels = getArrayDimensions(genericArrayType);
Type arrayComponentType = refineType(getArrayNestedComponentType(genericArrayType), typeVariablesMap);
return buildArrayType(arrayComponentType, levels);
}
For ParameterizedType its much simpler, we just refine type arguments, and create new ParameterizedType instance with these refined arguments:
private static Type refineParameterizedType(ParameterizedType parameterizedType, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
Type[] refinedTypeArguments = refineTypes(parameterizedType.getActualTypeArguments(), typeVariablesMap);
return new ResolvedParameterizedType(parameterizedType.getRawType(), refinedTypeArguments, parameterizedType.getOwnerType());
}
Same for WildcardType:
private static Type refineWildcardType(WildcardType wildcardType, Map<TypeVariable<?>, Type> typeVariablesMap) throws GenericsException {
Type[] refinedUpperBounds = refineTypes(wildcardType.getUpperBounds(), typeVariablesMap);
Type[] refinedLowerBounds = refineTypes(wildcardType.getLowerBounds(), typeVariablesMap);
return new ResolvedWildcardType(refinedUpperBounds, refinedLowerBounds);
}
And this leaves us with whole analyze function looking like this:
public static Type analyzeParameterizedTypes(final Class<?> klass, final Class<?> targetClass, final Class<?> rootClass, final int paramTypeNumber, Map<Integer, Type> childClassTypes) throws GenericsException {
Type superclassType = klass.getGenericSuperclass();
Map<TypeVariable<?>, Type> currentClassTypes = new HashMap<>();
int z = 0;
if (childClassTypes != null) {
for (TypeVariable<?> variable : klass.getTypeParameters()) {
currentClassTypes.put(variable, childClassTypes.get(z));
z++;
}
}
Map<Integer, Type> superClassesTypes = new HashMap<>();
if (superclassType instanceof ParameterizedType) {
int i = 0;
for (final Type argType : ((ParameterizedType) superclassType).getActualTypeArguments()) {
if (argType instanceof TypeVariable) {
superClassesTypes.put(i, currentClassTypes.getOrDefault(argType, argType));
} else {
superClassesTypes.put(i, refineType(argType, currentClassTypes));
}
i++;
}
}
if (klass != rootClass) {
final Class<?> superClass = klass.getSuperclass();
if (superClass == null)
throw new GenericsException(String.format("Class [%s] not found on class parent hierarchy [%s]", rootClass, targetClass));
return analyzeParameterizedTypes(superClass, targetClass, rootClass, paramTypeNumber, superClassesTypes);
}
return childClassTypes.get(paramTypeNumber);
}
Example usage:
private class SomeClass<A, B, C, D, E, F> {}
private class SomeConfusingClass<A> extends SomeClass<List<Void>[], List<? extends A>[], List<? extends A[][][]>[][][], List<? extends String[]>[], Map<List<? extends A[]>, A[][]>[], A> {}
private class TestClass extends SomeConfusingClass<Void> {}
public static void main(String[] args) throws Exception {
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 0));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 1));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 2));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 3));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 4));
System.out.println(GenericsUtils.getParameterizedType(TestClass.class, SomeClass.class, 5));
}
And results:
java.util.List<java.lang.Void>[]
java.util.List<? extends java.lang.Void>[]
java.util.List<? extends java.lang.Void[][][]>[][][]
java.util.List<? extends java.lang.String[]>[]
java.util.Map<java.util.List<? extends java.lang.Void[]>, java.lang.Void[][]>[]
class java.lang.Void
Whole code with tests can be found here: https://gist.github.com/GotoFinal/33b9e282f270dbfe61907aa830c27587 or here: https://github.com/GotoFinal/generics-utils/tree/edge-cases-1
Based on OP original answer code, but with most of edge cases covered.
The answer is: Java does not support reified generics, see this feature request from 2004 with lots of duplicates. See also:
C# has reified generics, Java does not
Kotlin reified generics example
Java generics, type erasure and again Kotlin's reified generics
So unless you want to switch to Kotlin, there is simply nothing you can do because generic type information in Java is available to the compiler only, not during runtime (reified generics).
I am sorry if you do not like the answer, but still it is correct as of Java 13 in early 2020.
I think a working solution would be to extend the one proposed by #naikus. It only needs to go up in the hierarchy on the constructor.
import java.lang.reflect.ParameterizedType;
public abstract class AbstractRequestHandler<I,O> {
protected I input;
protected O output;
protected Class<I> inputClass;
protected Class<O> outputClass;
protected AbstractRequestHandler() {
Class<?> clazz = getClass();
while (!clazz.getSuperclass().equals(AbstractRequestHandler.class)) {
clazz = clazz.getSuperclass();
}
ParameterizedType genericSuperclass = (ParameterizedType) clazz.getGenericSuperclass();
this.inputClass = (Class<I>) genericSuperclass.getActualTypeArguments()[0];
this.outputClass = (Class<O>) genericSuperclass.getActualTypeArguments()[1];
}
}
I've worked to an utility library that offers a method that generally solve the question analyzing recursively all parent classes hierarchy to get a specific generic type.
It is available on my GitHub project: https://github.com/gregorycallea/generics-utils
UPDATE: Thanks to #GoToFinal user that with his great effort improved the project covering also several differents complex
generics case ( such as GenericArrayType, ParameterizedType and
WildcardType).
For all details about these improvements see his answer on this question.
This is the summarized scenario the method works on:
Suppose you have a parameterized root class with an undefined number of generics defined.
Example: Let's consider as root class the following "Base" class that defines 3 generics:
private class Base<I, E, F> {
I var1;
E var2;
F var3;
}
NOTE: To each generic is assigned an index starting from 0. So index mapping for this class is:
I = 0
E = 1
F = 2
Suppose this root class have a complex and multi-leveled hierarchy of child classes.
Example:
// Base<I,E,F>
// BaseA<G,H> extends Base<H,Boolean,G>
// BaseB<T> extends BaseA<T,String>
// BaseC<H> extends BaseB<H>
// BaseD extends BaseC<Integer>
// BaseE extends BaseD
// BaseF extends BaseE
// BaseG extends BaseF
// BaseH<H> extends BaseG<H,Double>
// BaseI<T> extends BaseF<T>
// BaseL<J> extends BaseI<J>
// BaseM extends BaseL<Float>
// BaseN extends BaseM
NOTE: Notice that walking the child hierarchy new parameterized classes are defined and also some classes are not parameterized at all
Then suppose you want to choose whatever class on root class child hierarchy and then get the exactly type of a specific generic defined on root class starting from this.
Example:
You want to know the type of E generic ( with index = 1 ) defined on Base class starting from child class BaseN.
To do this you can simply execute the GenericsUtils.getParameterizedType method as follow:
Type targetType = GenericsUtils.getParameterizedType(GenericChildClass.class, RootClass.class, genericRootClassIndex);
Example:
Type EType = GenericsUtils.getParameterizedType(BaseN.class, Base.class, 1);
I evaluated several cases for this example scenario with unit tests.
Take a look at:
https://github.com/gregorycallea/generics-utils/blob/master/src/test/java/com/github/gregorycallea/generics/GenericsUtilsTest.java
About the initial scenario exposed on my question instead we can use this method on AbstractRequestHandler constructor as follow:
public abstract class AbstractRequestHandler<I,O> {
I input;
O output;
public AbstractRequestHandler(String inputJson) throws GenericsException {
this.input = new Gson().fromJson(inputJson,GenericsUtils.getParameterizedType(getClass(), AbstractRequestHandler.class, 0));
}
}

Java: How to get the class type of generics at runtime? [duplicate]

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.
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;
}
}
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
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.
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.
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;
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.
public abstract class AbstractDao<T>
{
private final Class<T> persistentClass;
public AbstractDao()
{
this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}
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();
}
}
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
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;
}
}
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:
You specify the generic type (PassedGenericType) in TWO places rather than one which is non-DRY.
This is only possible if you can modify the concrete subclasses.
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;
}
}
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);
}
}
}
}
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>() {};)
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.
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());
}
}
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());
}
}
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
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();
}
}
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();
// ...
}
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;
}
}
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.
Use an abstract method that returns the class type then use it in that class and wherever you extend generic class you will have to implement that abstract method to return the required class type
public class AbsractService<T>{
public abstract Class<T> getClassType ();
.......
}
at runtime
class AnimalService extends AbstractService<Animal>{
#Override
public Class<Animal> getClassType (){
return Animal.class;
}
.....
}
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}
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;
}
}
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.
}
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>
}
}
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.
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();
}
}
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);
}
}

Why this converter needs casting?

I need to implement an enum to enum converter in java: Enum_2 > Enum_1 and I'd like to do it in generic way.
So I defined an interface:
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
and Enum_1:
enum Enum_1 {
A, B;
String getValue() {
return "whatever";
}
}
and Enum_2 which implements LabelAware and needs to be converted to Enum_1:
enum Enum_2 implements LabelAware<Enum_1> {
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object) {
this.label = label;
this.object = object;
}
public String getLabel() {
return label;
}
public Enum_1 getObject() {
return object;
}
}
Finally, here's a generic converter (List.ofAll() comes from javaslang):
class Converter<S extends LabelAware, D extends Enum> {
private S[] values;
Converter(S[] values) {
this.values = values;
}
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
And a main method:
public class Main {
public static void main(String[] args) {
System.out.println(new Converter<Enum_2, Enum_1>(Enum_2.values()).map("c").getValue());
}
}
It all compiles and runs well, however I've no idea why I need to cast the result of Converter.map method to D, since I've declared D to extend Enum. Can it be done in a generic way without any warnings?
As a general rule, all warnings related to generics should be handled to have a safer code and avoid a warning chain (the visible warning is caused by a very far warning of the dependency chain).
But in your case, you have not a warning chain problem since externally, LabelAware is safe. LabelAware has only a internal warning (in its implementation) as Enum in extends Enum is raw-declared.
Here, a single missing generic declaration explains why the cast in Converter.map() method is not safe : Converter class declaration doesn't specify the generic for LabelAware.
You declare Converter class as :
class Converter<S extends LabelAware, D extends Enum> {
with its value field of type S:
private S[] values;
and its map() method as :
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
In map(), here .find(v -> v.getLabel().equals(label)), your retrieve so a S instance and you declared that S extends LabelAware.
Therefore finally, your retrieve an instance of LabelAware or extending it.
And LabelAware is typed with Enum generic :
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
So, in map() method when .map(LabelAware::getObject) is called, you retrieve a Enum type .
And an Enum type is not necessarily a D type, while the reverse is true.
Therefore, if you want to avoid the cast (and the related warning) in map(), you should specify that the generic type returned by getObject() is an instance of D by typing LabelAware with D generic :
class Converter<S extends LabelAware<D>, D extends Enum> {
You have been using raw types at several places (not only the one that yshavit pointed out in the comment). Particularly, the
class Converter<S extends LabelAware, D extends Enum>
has to be
class Converter<S extends LabelAware<D>, D extends Enum<D>>
The following should compile without warnings:
import javaslang.collection.List;
interface LabelAware<T extends Enum<?>>
{
String getLabel();
T getObject();
}
enum Enum_1
{
A, B;
String getValue()
{
return "whatever";
}
}
enum Enum_2 implements LabelAware<Enum_1>
{
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object)
{
this.label = label;
this.object = object;
}
public String getLabel()
{
return label;
}
public Enum_1 getObject()
{
return object;
}
}
class Converter<S extends LabelAware<D>, D extends Enum<D>>
{
private S[] values;
Converter(S[] values)
{
this.values = values;
}
D map(String label)
{
return List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
(EDIT: This only tells you how to fix the problem, pragmatically. See the answer by davidxxx for details about what went wrong there, and don't forget to leave a +1 there :-))

How to determine generic parameter of one of implemented interfaces?

I would like to have generic tagging interface, so that tag contain some class information.
Now, how to know with which class the given tag was parametrized with?
In the code below I am taking an object, then looking for tag MyClass2 and then wishing to extract the parameter of the tag (which is MyClass3)
package tests.java;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class Try_GenericRuntime {
public static class MyClass1 implements MyClass2<MyClass3>, MyClass4<MyClass5 >{
}
interface MyClass2<T> {
}
interface MyClass4<T> {
}
interface MyClass3 {
}
interface MyClass5 {
}
#SuppressWarnings("unchecked")
public static void main(String[] args) {
MyClass1 a = new MyClass1();
// how to derive/reach MyClass3?
Type[] ifaces = a.getClass().getGenericInterfaces();
Type iface;
Type[] params;
for(int i=0; i<ifaces.length; ++i) {
iface = ifaces[i];
if( ((Class)iface).isAssignableFrom(MyClass2.class) ) {
params = ((ParameterizedType)iface).getActualTypeArguments();
System.out.println(params[0].toString());
}
}
}
}
This code gives sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class exception message.
Other variants are also problematic due to incompatibilities between ParameterizedType and Class.
You can use getRawType() here:
for(int i=0; i<ifaces.length; ++i) {
iface = ifaces[i];
final ParameterizedType parameterizedType = (ParameterizedType) iface;
if(((Class<?>) parameterizedType.getRawType()).isAssignableFrom(MyClass2.class) ) {
params = parameterizedType.getActualTypeArguments();
System.out.println(params[0].toString());
}
}
Outputs interface tests.java.Try_GenericRuntime$MyClass3
This is straightforward using TypeTools (which I authored):
Class<?> typeArg = TypeResolver.resolveRawArgument(MyClass2.class, MyClass1.class);
assert typeArg == MyClass3.class;

Categories

Resources