How can I achieve this?
public class GenericClass
{
public Type getMyType()
{
//How do I return the type of T?
}
}
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 {
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 extends Class1 {
public B someB;
public D someD;
public E someE;
}
public static class Class3 extends Class2 {
public E someE;
}
public static class Class4 extends Class3 {
}
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, Type> subMap = new HashMap<>();
Class> superClass;
while ((superClass = subClass.getSuperclass()) != null) {
Map, 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;
}
}