Skip to main content

Getting a Java Type Parameter class at runtime

Certain use cases like deserializing a collection requires knowing the type of the declared field. As the common understanding goes, Type Parameters are erased at build time. So How do we get them?

Its a common misconception that "Type Parameters are erased at build time" - Instead what is actually happening is - Generic collections are converted to raw types. The class definition is NOT modified at build/run time. The Type Parameter(s) can be accessed from the class definition through reflection.

For example:

Lets say here is a Bean

public class Document {
 private List<Model> models;
        ..
}

Given doc, an instance of Document, at runtime, getting the type of doc.models by traditional reflection, can only get that its type is java.util.List

//somewhere in runtime
Document doc = new Document();

 Field f = bean.getClass().getDeclaredField(field);
 f.setAccessible(true);
 assert f.getClass() == List.class

To get the type from parameter, Assuming we know that it is a ParameterizedType (like List<T>)

private <T> Class getListType(T bean, String field) throws NoSuchFieldException {
 Class childType;
 Field f = bean.getClass().getDeclaredField(field);
 f.setAccessible(true);
 childType = (Class) ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0];
 return childType;
}

//somewhere in runtime
Document doc = new Document();
assert getListType(doc, "models") == Model.class


The same logic can be applied to get multi parameter types (like Map)

 keyType = (Class) ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[0];
 valueType = (Class) ((ParameterizedType) f.getGenericType()).getActualTypeArguments()[1];