Search code examples
javatype-variables

How can I get the type variable vs field mapping from a generic class?


I have a generic class as below, two type variables with three fields declared.

class RowClass<T1, T2> {
    public T1 t1;
    public T2 t2;
    public T1 t3;
}

Now I want to extract a mapping as this:

t1 -> T1; t2 -> T2; t3 -> T3

So I can know exactly which type variable each field is associated to. Below code will not work as generic erasure.

for (Field declaredField : RowClass.class.getDeclaredFields()) {
    System.out.println(declaredField.getName()+" -> " +declaredField.getType());
}
// t1 -> class java.lang.Object
// t2 -> class java.lang.Object
// t3 -> class java.lang.Object
// no type variable symbol printed

Why I ask this issue? Just for study, I am try to understand how Jackson deserialize json string to Class with declared generic type, sucn as List<String>.

first, I can get the type variable list:

// the list of type variable
final TypeVariable<Class<RowClass>>[] typeParameters = RowClass.class.getTypeParameters();
Arrays.stream(typeParameters).forEach(System.out::println);

Second, I can also get the list of actual arguments:

class RowClassImpl extends RowClass<String, Integer> {
}

final ParameterizedType parameterizedType = (ParameterizedType) (RowClassImpl.class.getGenericSuperclass());
Arrays.stream(parameterizedType.getActualTypeArguments()).forEach(type -> System.out.println(type.getTypeName()));

If I can get the type variable vs field mapping, I can preserve all the generic information for each field.


Solution

  • "... Now I want to extract a mapping as this:

    t1 -> T1; t2 -> T2; t3 -> T3 ..."

    You wrote that incorrectly, by the way.  It should be T1 for t3.

    Here is an example.

    RowClass<?, ?> r = new RowClass<>();
    Map<String, Type> m
        = Stream.of(r.getClass().getDeclaredFields())
                .collect(Collectors.toMap(Field::getName, Field::getGenericType));
    

    Output

    {t1=T1, t2=T2, t3=T1}