in wayang-commons/wayang-core/src/main/java/org/apache/wayang/core/util/ReflectionUtils.java [345:394]
public static Map<String, Type> getTypeParameters(Class<?> subclass, Class<?> superclass) {
// Gather implemented interfaces and superclass.
List<Type> genericSupertypes = Stream.concat(
Stream.of(subclass.getGenericSuperclass()), Stream.of(subclass.getGenericInterfaces())
).collect(Collectors.toList());
for (Type supertype : genericSupertypes) {
if (supertype instanceof Class<?>) {
// If the supertype is a Class, there are no type parameters to worry about.
Class<?> cls = (Class<?>) supertype;
if (!superclass.isAssignableFrom(cls)) continue;
return getTypeParameters(cls, superclass);
} else if (supertype instanceof ParameterizedType) {
// Handle type parameters.
ParameterizedType parameterizedType = (ParameterizedType) supertype;
final Type rawType = parameterizedType.getRawType();
if (!(rawType instanceof Class<?>)) continue;
Class<?> cls = (Class<?>) rawType;
if (!superclass.isAssignableFrom(cls)) continue;
final Map<String, Type> localTypeArguments = getTypeArguments(parameterizedType);
if (cls.equals(superclass)) {
// If we reached the superclass, we are good.
return localTypeArguments;
} else {
// If we are not there yet, we need to consider to "redirect" type parameters.
final Map<String, Type> preliminaryResult = getTypeParameters(cls, superclass);
final Map<String, Type> result = new HashMap<>(preliminaryResult.size());
for (Map.Entry<String, Type> entry : preliminaryResult.entrySet()) {
if (entry.getValue() instanceof TypeVariable<?>) {
final Type translatedTypeArgument = localTypeArguments.getOrDefault(
((TypeVariable) entry.getValue()).getName(),
entry.getValue()
);
result.put(entry.getKey(), translatedTypeArgument);
} else {
result.put(entry.getKey(), entry.getValue());
}
}
return result;
}
}
}
return Collections.emptyMap();
}