protected static HierarchicType _findSuperInterfaceChain(Type currentType, Class<?> target) { HierarchicType current = new HierarchicType(currentType); Class<?> raw = current.getRawClass(); if (raw == target) { return current; } // Otherwise, keep on going down the rat hole; first implemented interaces Type[] parents = raw.getGenericInterfaces(); // as long as there are superclasses // and unless we have already seen the type (<T extends X<T>>) if (parents != null) { for (Type parent : parents) { HierarchicType sup = _findSuperInterfaceChain(parent, target); if (sup != null) { sup.setSubType(current); current.setSuperType(sup); return current; } } } // and then super-class if any Type parent = raw.getGenericSuperclass(); if (parent != null) { HierarchicType sup = _findSuperInterfaceChain(parent, target); if (sup != null) { sup.setSubType(current); current.setSuperType(sup); return current; } } return null; }
protected static HierarchicType _findSuperClassChain(Type currentType, Class<?> target) { HierarchicType current = new HierarchicType(currentType); Class<?> raw = current.getRawClass(); if (raw == target) { return current; } // Otherwise, keep on going down the rat hole... Type parent = raw.getGenericSuperclass(); if (parent != null) { HierarchicType sup = _findSuperClassChain(parent, target); if (sup != null) { sup.setSubType(current); current.setSuperType(sup); return current; } } return null; }
protected static JavaType _resolveVariableViaSubTypes( HierarchicType leafType, String variableName, TypeBindings bindings) { // can't resolve raw types; possible to have as-of-yet-unbound types too: if (leafType != null && leafType.isGeneric()) { TypeVariable<?>[] typeVariables = leafType.getRawClass().getTypeParameters(); for (int i = 0, len = typeVariables.length; i < len; ++i) { TypeVariable<?> tv = typeVariables[i]; if (variableName.equals(tv.getName())) { // further resolution needed? Type type = leafType.asGeneric().getActualTypeArguments()[i]; if (type instanceof TypeVariable<?>) { return _resolveVariableViaSubTypes( leafType.getSubType(), ((TypeVariable<?>) type).getName(), bindings); } // no we're good for the variable (but it may have parameterization of its own) return instance._fromType(type, bindings); } } } return instance._unknownType(); }
/** * Method that is to figure out actual type parameters that given class binds to generic types * defined by given (generic) interface or class. This could mean, for example, trying to figure * out key and value types for Map implementations. * * @since 1.6 */ public static JavaType[] findParameterTypes(Class<?> clz, Class<?> expType) { // First: find full inheritance chain HierarchicType subType = _findSuperTypeChain(clz, expType); // Caller is supposed to ensure this never happens, so: if (subType == null) { throw new IllegalArgumentException( "Class " + clz.getName() + " is not a subtype of " + expType.getName()); } // Ok and then go to the ultimate super-type: HierarchicType superType = subType; while (superType.getSuperType() != null) { superType = superType.getSuperType(); } // which ought to be generic (if not, it's raw type) if (!superType.isGeneric()) { return null; } // Otherwise this becomes a recursive thing // otherwise need to start unwinding ParameterizedType pt = superType.asGeneric(); Type[] actualTypes = pt.getActualTypeArguments(); JavaType[] resultTypes = new JavaType[actualTypes.length]; // TODO: rewrite TypeBindings to also work properly with renaming, aliasing TypeBindings bindings = new TypeBindings(clz); for (int i = 0, len = actualTypes.length; i < len; ++i) { Type t = actualTypes[i]; // Only type variables need immediate resolution if (t instanceof TypeVariable<?>) { resultTypes[i] = _resolveVariableViaSubTypes( superType.getSubType(), ((TypeVariable<?>) t).getName(), bindings); } else { resultTypes[i] = instance._fromType(t, bindings); } } return resultTypes; }