Thanks for that code.
It think Ian know that but me (and I expect for those who will support my code in future) I did'nt figure it out right away.
public class A<T>
{
T woop;
}
public class B extends A<String>
{
}
with this JUnit:
@Test
public void testTypes()
{
final A<String> a1 = new A<String>();//type information not available because not available in class definition (plain definition of A, type undefined).
final A<String> a2 = new A<String>()
{};//type information preserved because included (defined) into annonymous class definition
final A<String> b1 = new B();//preserved because information provided in class definition
final Class<?> a1TypeClass = getTypeArguments(A.class, a1.getClass()).get(0);//null
final Class<?> a2TypeClass = getTypeArguments(A.class, a2.getClass()).get(0);//String
final Class<?> b1TypeClass = getTypeArguments(A.class, b1.getClass()).get(0);//String
assertNull("at run time this is a A instance, no value for parameter", a1TypeClass);
assertNotNull("Ok", a2TypeClass);
assertNotNull("Ok", b1TypeClass);
}
what was not clear to me it's that the class return by any instance is the class definition as found in source code. Not the instance declaration, this information is absent in the reflection universe.
But if parameter are defined in class definition either by explicit inheritance like the case B or by anonymous subclass (a2) then the information will be available.
in my usage of your code I'll add an explicit exception for this:
public static Class<?> getClass(final Type type)
{
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
} else if (type instanceof GenericArrayType) {
final Type componentType = ((GenericArrayType) type).getGenericComponentType();
final Class<?> componentClass = getClass(componentType);
if (componentClass != null) {
return Array.newInstance(componentClass, 0).getClass();
} else {
return null;
}
} else {
if (type instanceof TypeVariable<?>) {
throw new InvalidParameterException(
"Error parameter is not define in this class implementation, generic parameter is probably provided at class instanciation, need to be define at class definition (subclassing)");
}
return null;
}
}
To help future developer finding this issue since this 2 little brackets look like a bit weird alone and may get deleted by some cleanup
final A<String> a2 = new A<String>(){};