Retrieving type parameters from an instance of a generic base interface
This problem is not easy to fully solve in general. For example, you also have to take type parameters of the containing class into account if it's an inner class,...
Because reflection over generic types is so hard using just what Java itself provides, I wrote a library that does the hard work: gentyref. See http://code.google.com/p/gentyref/ For your example, using gentyref, you can do:
Type myType = MyClass.class;
// get the parameterized type, recursively resolving type parameters
Type baseType = GenericTypeReflector.getExactSuperType(myType, BaseInterface.class);
if (baseType instanceof Class<?>) {
// raw class, type parameters not known
// ...
} else {
ParameterizedType pBaseType = (ParameterizedType)baseType;
assert pBaseType.getRawType() == BaseInterface.class; // always true
Type typeParameterForBaseInterface = pBaseType.getActualTypeArguments()[0];
System.out.println(typeParameterForBaseInterface);
}
I don't know what exactly you are trying to achieve, and what is known and what not, but you can recurse to the superinterface like this:
Type[] interfaces = MyClass.class.getGenericInterfaces();
ParameterizedType extInterfaceType = (ParameterizedType)interfaces[0];
Class<?> extInterfaceClass = (Class<?>)extInterfaceType.getRawType();
Type[] baseInterfaces = extInterfaceClass.getGenericInterfaces();
ParameterizedType baseInterfaceType = (ParameterizedType)baseInterfaces[0];
Class<?> baseInterfaceClass = (Class<?>)baseInterfaceType.getRawType();
Of course if you reach the second level that way you get only your names T0 and T1 as generic parameters. If you know the relationship between ExtendedInterface
and BaseInterface
you don't really have to go that far since you know which generic parameter of the former is passed to the latter. If not, you probably would have to loop through their parameters and find a match. Something based on this probably:
Type[] params = extInterfaceClass.getTypeParameters();
for (Type param : params) {
if (param == baseInterfaceType.getActualTypeArguments()[0]) {
// ...
}
}
This is difficult to solve using Java Reflection API because one needs to resolve all encountered type variables. Guava since version 12 has TypeToken class which contains fully resolved type info.
For your example, you can do:
TypeToken<? extends T> token = TypeToken.of(MyClass.class);
ParameterizedType type =
(ParameterizedType) token.getSupertype(BaseInterface.class).getType();
Type[] parameters = type.getActualTypeArguments();
Still you need to remember that this only works for cases when MyClass is not generic itself. Otherwise the value of type parameters is not available at runtime due to type erasure.