Search code examples
javareflectiontype-erasurereification

Reflection: Applying type parameters of declaring class to fields


I have the below class structure:

class A<T,R> {
   B<R> b;
......
}

class B<R> {
   R t;
}

class StringConsumer {
   A<String, String> a;
}

class LongConsumer {
   A<Long, Long> a;
}

Given that I have an instance of one of the consumer classes, is it possible to obtain the type parameter(s) for consumer.a.b? I found that I am able to resolve the same if I declare a as StringA a; where class StringA extends A<String, String> using TypeTools


Solution

  • Since your consumer classes declare the field a with no type variables, all the typing information you need will be present at runtime.

    While it's possible to achieve what you're asking using reflection directly, it gets insane fast, so I'd highly recommend using GenTyRef or GeAnTyRef (an enhanced fork that I maintain).

    StringConsumer consumer = new StringConsumer(); //Or LongConsumer
    
    Field a = consumer.getClass().getDeclaredField("a");
    //typeOfA represents A<String, String>
    ParameterizedType typeOfA = (ParameterizedType) GenericTypeReflector.getExactFieldType(a, consumer.getClass());
    
    Type[] args =  typeOfA.getActualTypeArguments();
    System.out.println(args[0]); //String
    System.out.println(args[1]); //String
    
    Field b = A.class.getDeclaredField("b");
    //or if you need it dynamic ((Class)typeOfA.getRawType()).getDeclaredField("b")
    //or GenericTypeReflector.erase(typeOfA).getDeclaredField("b")
    //typeOfB represents B<String>
    ParameterizedType typeOfB = (ParameterizedType) GenericTypeReflector.getExactFieldType(b, typeOfA);
    System.out.println(typeOfB.getActualTypeArguments()[0]); //String again
    

    So what you do here is start from StringConsumer, get the type of its field a (typeOfA, which is A<String, String>), then use that information to get the type of field b (typeOfB, which is B<String>). You can go as deep as you need to this way...