I would like to request for an item class of collection (kind of specific reflection). But regarding to type erasure it seems not possible and also regarding to some topics I've read here on stack. There are some workarounds (here), but I'm curious if somebody know how is it done for example by DWR:
http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/signatures.html
or in case that there is some better workaround it would be great.
Let's say we have something like:
public String foo(List<String> possibleFoos) {
and all I need to is find out that parameter possibleFoos is list of Strings, not just List
While it's true that Java will erase types at runtime (thus turning
List<String>
into justList
), in many cases it actually does store the generic type in runtime allowing you to restore the information lost to erasure. You can retrieve the actual generic types for these:This means if you simply have an object of type List, there's nothing you can do to get it's generic type (
object.getClass()
will get youList
and that's it) - it's been permanently lost. But, if you're trying to figure out the generic type for a method argument or any of the above, you usually can by using reflection. As your case doesn't involve type variables or other complications, it's pretty straightforward to get the actual type:If you had a more parameters and a map instead:
The code would be similar:
It's safe to assume this is what DWR is using as well, as the types are method arguments.
Similar methods are available for other listed cases:
Class.getMethod(...).getGenericReturnType()
will get you the real return typeClass.getField(fieldName).getGenericType()
will get you the real type of the fieldClass.getGenericSuperClass()
will get you the real super typeClass.getGenericInterfaces()
will get you the real interface typesEquivalent methods exist allowing access to
AnnotatedType
(generic type plus annotations on the type usage) introduced in Java 8:Class.getMethod(...).getAnnotatedParameterTypes()
Class.getMethod(...).getAnnotatedReturnType()
Class.getField(fieldName).getAnnotatedType()
Class.getAnnotatedSuperClass()
Class.getAnnotatedInterfaces()
Now, this is all dandy when your case as simple as in the example. But, imagine if your example looked like this:
In this case,
getGenericParameterTypes()[0].getActualTypeArguments()[0]
would give youT
which is rather useless. To resolve whatT
stands for, you'd have to look into the class definition, and perhaps super classes, while keeping track of how the type variables are named in each class, as the names could be different in each.To make working with generic type reflection easier, you can use a wonderful library called GenTyRef that does the hard work for you, and if you need support for
AnnotatedType
s, you can use my fork called GeAnTyRef (both are in Maven Central). They also include a type factory, that allows you to construct instances of(Annotated)Type
, which you can not easily do using normal Java API. There's also a handy super type token implementation allowing you to get an(Annotated)Type
literal.With those, you can do everything with generic types that Java allows without the hassle I explained above:
GenericTypeReflector#getExactParameterTypes( ... )
GenericTypeReflector#getExactReturnType( ... )
GenericTypeReflector#getExactFieldType( ... )
GenericTypeReflector#getExactSuperType( ... )
And many more operations, like figuring out if one
Type
is a super type of another (similar toClass#isAssignableFrom
but for generic types), resolving specific type variables etc.