下面列出了怎么用java.lang.reflect.ParameterizedType的API类实例代码及写法,或者点击链接到github查看源代码。
protected boolean isDecoratableList(Field field) {
if (!List.class.isAssignableFrom(field.getType())) {
return false;
}
// Type erasure in Java isn't complete. Attempt to discover the generic
// type of the list.
Type genericType = field.getGenericType();
if (!(genericType instanceof ParameterizedType)) {
return false;
}
Type listType = ((ParameterizedType) genericType).getActualTypeArguments()[0];
if (!WebElement.class.equals(listType)) {
return false;
}
return field.getAnnotation(FindBy.class) != null ||
field.getAnnotation(FindBys.class) != null ||
field.getAnnotation(FindAll.class) != null;
}
public static boolean hasUnresolvableType(Type type) {
if (type instanceof Class<?>) {
return false;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
if (hasUnresolvableType(typeArgument)) {
return true;
}
}
return false;
}
if (type instanceof GenericArrayType) {
return hasUnresolvableType(((GenericArrayType) type).getGenericComponentType());
}
if (type instanceof TypeVariable) {
return true;
}
if (type instanceof WildcardType) {
return true;
}
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " + "GenericArrayType, but <" + type + "> is of type " + className);
}
private boolean isTypeMatch(Type type, Type targetType) {
if (type instanceof Class && targetType instanceof Class) {
if (((Class) type).isAssignableFrom((Class) targetType)) {
return true;
}
} else if (type instanceof ParameterizedType && targetType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
ParameterizedType parameterizedTargetType = (ParameterizedType) targetType;
if (isTypeMatch(parameterizedType.getRawType(), ((ParameterizedType) targetType).getRawType())) {
Type[] types = parameterizedType.getActualTypeArguments();
Type[] targetTypes = parameterizedTargetType.getActualTypeArguments();
if (types == null || targetTypes == null || types.length != targetTypes.length) {
return false;
}
int len = types.length;
for (int i = 0; i < len; i++) {
if (!isTypeMatch(types[i], targetTypes[i])) {
return false;
}
}
return true;
}
}
return false;
}
/**
* Converts a binding for a {@code Key<TypeLiteral<T>>} to the value {@code TypeLiteral<T>}. It's
* a bit awkward because we have to pull out the inner type in the type literal.
*/
private <T> BindingImpl<TypeLiteral<T>> createTypeLiteralBinding(
Key<TypeLiteral<T>> key, Errors errors) throws ErrorsException {
Type typeLiteralType = key.getTypeLiteral().getType();
if (!(typeLiteralType instanceof ParameterizedType)) {
throw errors.cannotInjectRawTypeLiteral().toException();
}
ParameterizedType parameterizedType = (ParameterizedType) typeLiteralType;
Type innerType = parameterizedType.getActualTypeArguments()[0];
// this is unforunate. We don't support building TypeLiterals for type variable like 'T'. If
// this proves problematic, we can probably fix TypeLiteral to support type variables
if (!(innerType instanceof Class)
&& !(innerType instanceof GenericArrayType)
&& !(innerType instanceof ParameterizedType)) {
throw errors.cannotInjectTypeLiteralOf(innerType).toException();
}
@SuppressWarnings("unchecked") // by definition, innerType == T, so this is safe
TypeLiteral<T> value = (TypeLiteral<T>) TypeLiteral.get(innerType);
InternalFactory<TypeLiteral<T>> factory = new ConstantFactory<TypeLiteral<T>>(
Initializables.of(value));
return new InstanceBindingImpl<TypeLiteral<T>>(this, key, SourceProvider.UNKNOWN_SOURCE,
factory, ImmutableSet.<InjectionPoint>of(), value);
}
public static Class<?> getGenericClass(Class<?> cls, int i) {
try {
ParameterizedType parameterizedType = ((ParameterizedType) cls.getGenericInterfaces()[0]);
Object genericClass = parameterizedType.getActualTypeArguments()[i];
if (genericClass instanceof ParameterizedType) { // 处理多级泛型
return (Class<?>) ((ParameterizedType) genericClass).getRawType();
} else if (genericClass instanceof GenericArrayType) { // 处理数组泛型
return (Class<?>) ((GenericArrayType) genericClass).getGenericComponentType();
} else if (genericClass != null) {
return (Class<?>) genericClass;
}
} catch (Throwable e) {
}
if (cls.getSuperclass() != null) {
return getGenericClass(cls.getSuperclass(), i);
} else {
throw new IllegalArgumentException(cls.getName() + " generic type undefined!");
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void writeTo(Optional<?> entity,
Class<?> type,
Type genericType,
Annotation[] annotations,
MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders,
OutputStream entityStream)
throws IOException {
if (!entity.isPresent()) {
throw new NotFoundException();
}
final Type innerGenericType = (genericType instanceof ParameterizedType) ?
((ParameterizedType) genericType).getActualTypeArguments()[0] : entity.get().getClass();
MessageBodyWriter writer = mbw.get().getMessageBodyWriter(entity.get().getClass(),
innerGenericType, annotations, mediaType);
writer.writeTo(entity.get(), entity.get().getClass(),
innerGenericType, annotations, mediaType, httpHeaders, entityStream);
}
/**
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
* 如无法找到, 返回Object.class.
*
* 如public UserDao extends HibernateDao<User,Long>
*
* @param clazz clazz The class to introspect
* @param index the Index of the generic ddeclaration,start from 0.
* @return the index generic declaration, or Object.class if cannot be determined
*/
@SuppressWarnings("rawtypes")
public static Class getClassGenricType(final Class clazz, final int index) {
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
logger.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return Object.class;
}
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
if ((index >= params.length) || (index < 0)) {
logger.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+ params.length);
return Object.class;
}
if (!(params[index] instanceof Class)) {
logger.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index];
}
@SuppressWarnings("unchecked")
public void addExceptionMapper(ObjectFactory<ProviderDescriptor> exceptionMapperFactory) {
for (Type type : exceptionMapperFactory.getObjectModel().getObjectClass().getGenericInterfaces()) {
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType)type;
if (ExceptionMapper.class == parameterizedType.getRawType()) {
Type[] typeArguments = parameterizedType.getActualTypeArguments();
if (typeArguments.length != 1) {
throw new RuntimeException("Unable strong determine actual type argument");
}
Class<? extends Throwable> errorType = (Class<? extends Throwable>)typeArguments[0];
if (exceptionMappers.putIfAbsent(errorType, exceptionMapperFactory) != null) {
throw new DuplicateProviderException(String.format("ExceptionMapper for exception %s already registered", errorType));
}
}
}
}
}
private int getPriority(final EventMapping mapping, final Type type) {
if (mapping.priority() != EventMapping.DEFAULT_PRIORITY_VALUE) {
return mapping.priority();
}
if (type == Event.class) {
return EventMapping.DEFAULT_PRIORITY_FOR_EVENT_IFACE;
}
if (type instanceof Class) {
return ((Class<?>) type).isInterface()
? EventMapping.DEFAULT_PRIORITY_FOR_IFACE
: EventMapping.DEFAULT_PRIORITY_FOR_CLASS;
}
if (type instanceof ParameterizedType) {
return EventMapping.DEFAULT_PRIORITY_FOR_PARAMETRIZED_TYPE;
}
throw new IllegalStateException();
}
protected static Pair<String, Class<? extends Object>> getChildInfo(Class target) {
Field[] declaredFields = target.getDeclaredFields();
for (Field field : declaredFields) {
final Class<?> type = field.getType();
if (type.isAssignableFrom(Collection.class)) {
final ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
String clazz = null;
try {
clazz = parameterizedType.getActualTypeArguments()[0].getTypeName();
return new Pair(field.getName(), Class.forName(clazz));
} catch (ClassNotFoundException ex) {
throw new IllegalStateException("Cannot find class " + clazz, ex);
}
}
}
return null;
}
@SuppressWarnings("unchecked")
public <T> T getListWith(ObjectMapper mapper, TypeReference<T> t) throws IOException {
if (opaque != null) {
Type c = t.getType();
if (c instanceof ParameterizedType) {
c = ((ParameterizedType)c).getRawType();
}
if ( c.equals(opaque.getClass())) {
return (T) opaque;
} else {
throw new IOException(String.format("Attempted to retrieve a list with type of %s. However, the JSON " +
"options carried an opaque value of type %s.", t.getType(), opaque.getClass().getName()));
}
}
if (root == null) {
return null;
}
return mapper.treeAsTokens(root).readValueAs(t);
}
public static Type canonicalize(Type type) {
if (type instanceof Class) {
Class<?> c = (Class) type;
return c.isArray() ? new GenericArrayTypeImpl(C$Gson$Types.canonicalize(c.getComponentType())) : c;
} else if (type instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) type;
return new ParameterizedTypeImpl(p.getOwnerType(), p.getRawType(), p.getActualTypeArguments());
} else if (type instanceof GenericArrayType) {
return new GenericArrayTypeImpl(((GenericArrayType) type).getGenericComponentType());
} else {
if (!(type instanceof WildcardType)) {
return type;
}
WildcardType w = (WildcardType) type;
return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
}
}
private <T> T deserializeObject(Object object, Type type) throws JSONException {
if (JSONObject.NULL == object) {
return null;
}
if (!(object instanceof JSONObject)) {
return (T) object;
}
JSONObject jsonObject = (JSONObject) object;
if (JSONPojo.class.equals(type)) {
JSONPojo result = new JSONPojo();
result.pojoInt = jsonObject.getInt("pojoInt");
result.pojoDouble = jsonObject.getDouble("pojoDouble");
result.pojoStr = jsonObject.getString("pojoStr");
result.pojoList = deserializeArray(jsonObject.getJSONArray("pojoList"), Integer.class);
return (T) result;
} else if (type instanceof ParameterizedType && Map.class
.equals(((ParameterizedType) type).getRawType())) {
return (T) deserializeMap(jsonObject, ((ParameterizedType) type).getActualTypeArguments()[1]);
}
throw new JSONException("Unable to parse object " + object);
}
private Type getOptionalGenericType(Type type) {
if (Optional.class.equals(type)) {
return Object.class;
}
if (!(type instanceof ParameterizedType)) {
return null;
}
ParameterizedType parameterizedType = (ParameterizedType) type;
if (Optional.class.equals(parameterizedType.getRawType())) {
return parameterizedType.getActualTypeArguments()[0];
}
return null;
}
@Override
public List<GraphQLArgument> call(@Nullable Field field, Method method, Class declaringClass, Annotation annotation) {
// if same annotation is detected on both field and getter we fail. Only one annotation is allowed. We can talk about having precedence logic later.
if (method.isAnnotationPresent(annotation.annotationType()) && field != null && field.isAnnotationPresent(annotation.annotationType())) {
throw new IllegalArgumentException("Conflict: GraphQL Annotations can't be added to both field and getter. Pick one for "+
annotation.annotationType() + " on " + field.getName() + " and " + method.getName());
}
Type returnType = GenericTypeReflector.getExactReturnType(method, declaringClass);
if (returnType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) returnType;
Type containerType = parameterizedType.getRawType();
if (Collection.class.isAssignableFrom((Class) containerType)) {
List<GraphQLArgument> arguments = new ArrayList<>();
arguments.add(newArgument().name(GlitrForwardPagingArguments.FIRST).type(GraphQLInt).build());
arguments.add(newArgument().name(GlitrForwardPagingArguments.AFTER).type(GraphQLString).build());
return arguments;
}
}
return new ArrayList<>();
}
@Override
public TypeBuilder name(Type type) {
if ( type instanceof Class) {
return name((Class<?>)type);
} else {
if ( type instanceof ParameterizedType ) {
ParameterizedType pt = (ParameterizedType) type;
if ( pt.getRawType() instanceof Class && Collection.class.isAssignableFrom((Class)pt.getRawType()) && pt.getActualTypeArguments().length == 1) {
Class<?> cls = (Class<?>) pt.getActualTypeArguments()[0];
TypeBuilder builder = name(cls);
return TypeBuilder.arrayOf(builder);
} else {
throw new IllegalArgumentException("can't parse type " + pt);
}
} else {
throw new IllegalArgumentException("can't parse type " + type);
}
}
}
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
Class<?> rawType = getRawType(type);
boolean isMono = rawType == Mono.class;
if (rawType != Flux.class && !isMono) {
if (rawType == Response.class) {
Type publisherType = getParameterUpperBound(0, (ParameterizedType) type);
Class<?> rawPublisherType = getRawType(publisherType);
isMono = rawPublisherType == Mono.class;
boolean isFlux = rawPublisherType == Flux.class;
if (isMono || isFlux) {
return EMPTY_CONVERTER;
}
}
return null;
}
return EMPTY_CONVERTER;
}
public static Type processGenericTypeIfNeeded(Class<?> serviceCls, Class<?> paramCls, Type type) {
if (type instanceof TypeVariable) {
type = InjectionUtils.getSuperType(serviceCls, (TypeVariable<?>)type);
} else if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)type;
if (pt.getActualTypeArguments()[0] instanceof TypeVariable
&& isSupportedCollectionOrArray(getRawType(pt))) {
TypeVariable<?> typeVar = (TypeVariable<?>)pt.getActualTypeArguments()[0];
Type theType = InjectionUtils.getSuperType(serviceCls, typeVar);
if (theType instanceof Class) {
type = new ParameterizedCollectionType((Class<?>)theType);
} else {
type = processGenericTypeIfNeeded(serviceCls, paramCls, theType);
type = new ParameterizedCollectionType(type);
}
}
}
if (type == null || type == Object.class) {
type = paramCls;
}
return type;
}
private void generateControl(Class clazz) {
Type type = clazz.getGenericSuperclass(); //获得带有泛型的父类
if (type instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) type; //获得参数化类型,即泛型
Type[] arrayClasses = p.getActualTypeArguments(); //获取参数化类型的数组,泛型可能有多个
for (Type item : arrayClasses) {
if (item instanceof Class) {
Class<T> tClass = (Class<T>) item;
if (tClass.equals(BaseControl.class) || (tClass.getSuperclass() != null &&
tClass.getSuperclass().equals(BaseControl.class))) {
messageProxy = new MessageProxy(mHandler);
mControl = ControlFactory.getControlInstance(tClass, messageProxy);
mModel = new ModelMap();
mControl.setModel(mModel);
return;
}
}
}
}
}
public Type onParameterizdType(ParameterizedType p, BinderArg args) {
Type[] params = p.getActualTypeArguments();
boolean different = false;
for (int i = 0; i < params.length; i++) {
Type t = params[i];
params[i] = visit(t, args);
different |= t != params[i];
}
Type newOwner = p.getOwnerType();
if (newOwner != null) {
newOwner = visit(newOwner, args);
}
different |= p.getOwnerType() != newOwner;
if (!different) {
return p;
}
return new ParameterizedTypeImpl((Class<?>) p.getRawType(), params, newOwner);
}
public Type onParameterizdType(ParameterizedType p, BinderArg args) {
Type[] params = p.getActualTypeArguments();
boolean different = false;
for (int i = 0; i < params.length; i++) {
Type t = params[i];
params[i] = visit(t, args);
different |= t != params[i];
}
Type newOwner = p.getOwnerType();
if (newOwner != null) {
newOwner = visit(newOwner, args);
}
different |= p.getOwnerType() != newOwner;
if (!different) {
return p;
}
return new ParameterizedTypeImpl((Class<?>) p.getRawType(), params, newOwner);
}
/**
* Returns the generic type at the given position for the given interface.
*
* @param instance the implementing instance
* @param iface the generic interface
* @param position the generic position
* @return the generic type at the given position
*/
public static Type getGenericInterfaceType(Object instance, Class<?> iface, int position) {
Class<?> type = instance.getClass();
while (type != Object.class) {
for (Type genericType : type.getGenericInterfaces()) {
if (genericType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericType;
if (parameterizedType.getRawType() == iface) {
return parameterizedType.getActualTypeArguments()[position];
}
}
}
type = type.getSuperclass();
}
return null;
}
/**
* 提取实际的泛型参数数组.
*
* @param parameterizedType
* the parameterized type
* @return 如果 <code>parameterizedType</code> 是null,抛出 {@link NullPointerException}<br>
* 如果 <code>parameterizedType</code> 没有实际的泛型参数 {@link ParameterizedType#getActualTypeArguments()},抛出
* {@link NullPointerException}<br>
* @see java.lang.reflect.ParameterizedType#getActualTypeArguments()
* @since 1.1.1
*/
private static Class<?>[] extractActualTypeArgumentClassArray(ParameterizedType parameterizedType){
Validate.notNull(parameterizedType, "parameterizedType can't be null/empty!");
if (LOGGER.isTraceEnabled()){
LOGGER.trace("parameterizedType info:[{}]", parameterizedType);
}
//---------------------------------------------------------------
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Validate.notNull(actualTypeArguments, "actualTypeArguments can't be null/empty!");
//---------------------------------------------------------------
if (LOGGER.isTraceEnabled()){
LOGGER.trace("actualTypeArguments:[{}]", ConvertUtil.toString(actualTypeArguments, ToStringConfig.DEFAULT_CONNECTOR));
}
return convert(actualTypeArguments, Class[].class);
}
/**
* Resolves all type variables in {@code type} and all downstream types and returns a
* corresponding type with type variables resolved.
*/
public Type resolveType(Type type) {
checkNotNull(type);
if (type instanceof TypeVariable) {
return typeTable.resolve((TypeVariable<?>) type);
} else if (type instanceof ParameterizedType) {
return resolveParameterizedType((ParameterizedType) type);
} else if (type instanceof GenericArrayType) {
return resolveGenericArrayType((GenericArrayType) type);
} else if (type instanceof WildcardType) {
return resolveWildcardType((WildcardType) type);
} else {
// if Class<?>, no resolution needed, we are done.
return type;
}
}
private Class<?> resolveClass(Type type, Class<?> subType) {
if (type instanceof Class) {
return (Class<?>) type;
} else if (type instanceof ParameterizedType) {
return resolveClass(((ParameterizedType) type).getRawType(), subType);
} else if (type instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType) type;
Class<?> component = resolveClass(gat.getGenericComponentType(), subType);
return Array.newInstance(component, 0).getClass();
} else if (type instanceof TypeVariable<?>) {
TypeVariable<?> variable = (TypeVariable<?>) type;
Type resolvedType = getTypeVariableMap(subType).get(variable);
return (resolvedType == null) ? resolveClass(resolveBound(variable), subType)
: resolveClass(resolvedType, subType);
} else if (type instanceof WildcardType) {
WildcardType wcType = (WildcardType) type;
Type[] bounds = wcType.getLowerBounds().length == 0 ? wcType.getUpperBounds()
: wcType.getLowerBounds();
return resolveClass(bounds[0], subType);
}
// there are no more types in a standard JDK
throw new IllegalArgumentException("Unknown type: " + type);
}
private static Class<?> toRawType(Type type) {
if (type instanceof Class) {
return (Class<?>) type;
}
if (type instanceof ParameterizedType) {
return (Class<?>) ((ParameterizedType) type).getRawType();
}
throw new IllegalArgumentException("Unsupported or invalid parameter type: " + type);
}
@Override
public void check(Field field) throws CodeCheckException {
Class<?> type = field.getType();
if (!Collection.class.isAssignableFrom(type) && !Map.class.isAssignableFrom(type)) {
assertFieldValid(field);
} else {
checkFieldCollectionOrMap(field, (ParameterizedType) field.getGenericType());
}
}
/**
* <p> Tries to determine the type arguments of a class/interface based on a
* super parameterized type's type arguments. This method is the inverse of
* {@link #getTypeArguments(Type, Class)} which gets a class/interface's
* type arguments based on a subtype. It is far more limited in determining
* the type arguments for the subject class's type variables in that it can
* only determine those parameters that map from the subject {@link Class}
* object to the supertype. </p> <p> Example: {@link java.util.TreeSet
* TreeSet} sets its parameter as the parameter for
* {@link java.util.NavigableSet NavigableSet}, which in turn sets the
* parameter of {@link java.util.SortedSet}, which in turn sets the
* parameter of {@link Set}, which in turn sets the parameter of
* {@link java.util.Collection}, which in turn sets the parameter of
* {@link java.lang.Iterable}. Since <code>TreeSet</code>'s parameter maps
* (indirectly) to <code>Iterable</code>'s parameter, it will be able to
* determine that based on the super type <code>Iterable<? extends
* Map<Integer,? extends Collection<?>>></code>, the parameter of
* <code>TreeSet</code> is <code>? extends Map<Integer,? extends
* Collection<?>></code>. </p>
*
* @param cls the class whose type parameters are to be determined
* @param superType the super type from which <code>cls</code>'s type
* arguments are to be determined
* @return a map of the type assignments that could be determined for the
* type variables in each type in the inheritance hierarchy from
* <code>type</code> to <code>toClass</code> inclusive.
*/
public static Map<TypeVariable<?>, Type> determineTypeArguments(Class<?> cls,
ParameterizedType superType) {
Class<?> superClass = getRawType(superType);
// compatibility check
if (!isAssignable(cls, superClass)) {
return null;
}
if (cls.equals(superClass)) {
return getTypeArguments(superType, superClass, null);
}
// get the next class in the inheritance hierarchy
Type midType = getClosestParentType(cls, superClass);
// can only be a class or a parameterized type
if (midType instanceof Class<?>) {
return determineTypeArguments((Class<?>) midType, superType);
}
ParameterizedType midParameterizedType = (ParameterizedType) midType;
Class<?> midClass = getRawType(midParameterizedType);
// get the type variables of the mid class that map to the type
// arguments of the super class
Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
// map the arguments of the mid type to the class type variables
mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
return typeVarAssigns;
}
/**
* <p> Closest parent type? Closest to what? The closest parent type to the
* super class specified by <code>superClass</code>. </p>
*
* @param cls the class in question
* @param superClass the super class
* @return the closes parent type
*/
private static Type getClosestParentType(Class<?> cls, Class<?> superClass) {
// only look at the interfaces if the super class is also an interface
if (superClass.isInterface()) {
// get the generic interfaces of the subject class
Type[] interfaceTypes = cls.getGenericInterfaces();
// will hold the best generic interface match found
Type genericInterface = null;
// find the interface closest to the super class
for (Type midType : interfaceTypes) {
Class<?> midClass = null;
if (midType instanceof ParameterizedType) {
midClass = getRawType((ParameterizedType) midType);
} else if (midType instanceof Class<?>) {
midClass = (Class<?>) midType;
} else {
throw new IllegalStateException("Unexpected generic"
+ " interface type found: " + midType);
}
// check if this interface is further up the inheritance chain
// than the previously found match
if (isAssignable(midClass, superClass)
&& isAssignable(genericInterface, (Type) midClass)) {
genericInterface = midType;
}
}
// found a match?
if (genericInterface != null) {
return genericInterface;
}
}
// none of the interfaces were descendants of the target class, so the
// super class has to be one, instead
return cls.getGenericSuperclass();
}
/**
* If type is a parameterized type, searches the given type variable in the list
* of declared type variables, and then returns the corresponding actual type.
* Returns null if the type variable is not defined by type.
*/
private static Type matchTypeVariable(Type type, TypeVariable<?> variable) {
if (type instanceof ParameterizedType) {
Class<?> rawInterfaceType = getRawType(type);
TypeVariable<?>[] typeParameters = rawInterfaceType.getTypeParameters();
for (int i = 0; i < typeParameters.length; i++) {
if (variable.equals(typeParameters[i])) {
return ((ParameterizedType) type).getActualTypeArguments()[i];
}
}
}
return null;
}