Here's an example, first, let's define a simple class:
import java.util.List;
public class GenericsTest {
public GenericsTest() {
this.stringList = null;
this.stringField = null;
}
private List<String> stringList;
private String stringField;
}
And now for our test:
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class FieldGenericsTest {
public static void main(String[] args) throws Exception {
GenericsTest gt = new GenericsTest();
Field[] fields = gt.getClass().getDeclaredFields();
for (Field field : fields) {
// needed to access non-public fields
field.setAccessible(true);
Type fieldType = field.getType(); // will be List without generics
System.out.println("field type: " + fieldType);
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
Type[] types = pt.getActualTypeArguments();
// since we only have one generic type in our example, that is,
// List<String> contains only one generic type parameter, the
// size of this array will only be one.
Type type = types[0];
if (type.equals(String.class)) {
System.out.println("generic type is string: " + type);
}
}
else {
// fields without generics will fall here
System.out.println("not a parameterized type: " + genericType);
}
}
}
}
This, by itself, is pretty powerful for the use cases where the generic type needs to be known at run-time. But, what if you have multiple fields with the same type/generic signature? That is, we have two fields with the type List<String>. We can use annotations to distinguish these fields apart and then access the annotations while we're iterating over the fields. My next post will deal with that use case.