我回答我自己的问题又是不礼貌的行为。
正如 gix 指出的,当您开始遍历泛型类型的层次结构时,除了第一个之外,您会丢失有关类型参数的信息。
但重要的一点是:您获得了第一个要实例化的通用接口的类型参数(在我的示例中,ExtendedInterface),您还获得了用于创建子接口的类型参数的名称。
因此,可以通过将 TypeVariable 名称映射到实际类型参数来确定基本接口的类型参数。
稍后我会更新一些代码,但它确实有效(您可以从 MyClass.class 中确定用于实例 BaseInterface 的类型参数)。
更新
这是第一次通过,为一些简单的单元测试开了绿灯。它需要工作......真正的问题是,这个问题值得这样荒谬的解决方案吗?
public class GenericReflectionUtils
{
@SuppressWarnings("unchecked")
public static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, Class concreteClass)
{
if (!baseInterface.isAssignableFrom(concreteClass))
{
throw new IllegalArgumentException("Illegal base interface argument");
}
if (concreteClass.getTypeParameters().length > 0)
{
throw new IllegalArgumentException("Can't determine the type arguments of a generic interface of a generic class");
}
for (Type genericInterface : concreteClass.getGenericInterfaces())
{
List<Class> result = null;
if (genericInterface instanceof Class)
{
result = getGenericInterfaceTypeArguments(baseInterface,(Class)genericInterface);
}
else
{
result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterface);
}
if (result != null)
{
return result;
}
}
return null;
}
public static Class getClass(Type type)
{
if (type instanceof Class)
{
return (Class) type;
}
if (type instanceof ParameterizedType)
{
return getClass(((ParameterizedType) type).getRawType());
}
if (type instanceof GenericArrayType)
{
Type componentType = ((GenericArrayType) type).getGenericComponentType();
Class<?> componentClass = getClass(componentType);
if (componentClass != null)
{
return Array.newInstance(componentClass, 0).getClass();
}
return null;
}
return null;
}
@SuppressWarnings("unchecked")
private static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, ParameterizedType currentType)
{
Class currentClass = getClass(currentType);
if (!baseInterface.isAssignableFrom(currentClass))
{
// Early out - current type is not an interface that extends baseInterface
return null;
}
Type[] actualTypeArguments = currentType.getActualTypeArguments();
if (currentClass == baseInterface)
{
// currentType is a type instance of the base generic interface. Read out the type arguments and return
ArrayList<Class> typeArgs = new ArrayList<Class>(actualTypeArguments.length);
for (Type typeArg : actualTypeArguments)
{
typeArgs.add(getClass(typeArg));
}
return typeArgs;
}
// currentType is derived
Map<String, Class> typeVarMap = createTypeParameterMap(currentType, null);
for (Type genericInterfaceType : currentClass.getGenericInterfaces())
{
List<Class> result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterfaceType, typeVarMap);
if (result != null)
{
return result;
}
}
return null;
}
private static Map<String, Class> createTypeParameterMap(ParameterizedType type, Map<String, Class> extendedTypeMap)
{
Map<String, Class> typeVarMap = new HashMap<String, Class>();
Type[] typeArgs = type.getActualTypeArguments();
TypeVariable[] typeVars = getClass(type).getTypeParameters();
for (int typeArgIndex = 0; typeArgIndex < typeArgs.length; ++typeArgIndex)
{
// Does not deal with nested generic arguments...
Type typeArg = typeArgs[typeArgIndex];
if (typeArg instanceof TypeVariable)
{
assert extendedTypeMap != null;
TypeVariable typeVar = (TypeVariable)typeArg;
typeVarMap.put(typeVars[typeArgIndex].getName(), extendedTypeMap.get(typeVar.getName()));
continue;
}
typeVarMap.put(typeVars[typeArgIndex].getName(), getClass(typeArgs[typeArgIndex]));
}
return typeVarMap;
}
private static List<Class> createTypeParameterList(Map<String, Class> typeParameterMap, ParameterizedType type)
{
ArrayList<Class> typeParameters = new ArrayList<Class>(typeParameterMap.size());
for (Type actualType : type.getActualTypeArguments())
{
if (actualType instanceof TypeVariable)
{
// Handles the case when an interface is created with a specific type, rather than a parameter
typeParameters.add(typeParameterMap.get(((TypeVariable)actualType).getName()));
continue;
}
typeParameters.add(getClass(actualType));
}
return typeParameters;
}
@SuppressWarnings("unchecked")
private static List<Class> getGenericInterfaceTypeArguments(Class baseInterface, ParameterizedType currentType, Map<String, Class> currentTypeParameters)
{
Class currentClass = getClass(currentType);
if (!baseInterface.isAssignableFrom(currentClass))
{
// Early out - current type is not an interface that extends baseInterface
return null;
}
if (currentClass == baseInterface)
{
return createTypeParameterList(currentTypeParameters, currentType);
}
currentTypeParameters = createTypeParameterMap(currentType, currentTypeParameters);
for (Type genericInterface : currentClass.getGenericInterfaces())
{
List<Class> result = getGenericInterfaceTypeArguments(baseInterface, (ParameterizedType)genericInterface, currentTypeParameters);
if (result != null)
{
return result;
}
}
return null;
}
}