/** * Method to resolve a TypeVariable to its most <a * href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> * form. * * <p>How to resolve a TypeVariable:<br> * All of the TypeVariables defined by a generic class will be given a Type by any class that * extends it. The Type given may or may not be reifiable; it may be another TypeVariable for * instance. * * <p>Consider <br> * <i>class Pair>A,B> { A getA(){...}; ...}</i><br> * <i>class StringLongPair extends Pair>String, Long> { }</i><br> * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A". * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of * TypeVariables. * * <p>To get to the Type provided by StringLongPair you access the generics information by calling * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType * gives you access to the actual type arguments provided to Pair by StringLongPair. The array is * in the same order as the array in Pair.class.getTypeParameters so you can use the index we * discovered earlier to extract the Type; String.class. * * <p>When extracting Types we only have to consider the superclass hierarchy and not the * interfaces implemented by the class. When a class implements a generic interface it must * provide types for the interface and any generic methods implemented from the interface will be * re-defined by the class with its generic type variables. * * @param typeVariable - the type variable to resolve. * @param containingType - the shallowest class in the class hierarchy (furthest from Object) * where typeVariable is defined. * @return a Type that has had all possible TypeVariables resolved that have been defined between * the type variable declaration and the containingType. */ private static Type resolve(TypeVariable typeVariable, Type containingType) { // The generic declaration is either a Class, Method or Constructor final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); if (!(genericDeclaration instanceof Class)) { // It's a method or constructor. The best we can do here is try to resolve the bounds // e.g. <T extends E> T getT(T param){} where E is defined by the class. final Type bounds0 = typeVariable.getBounds()[0]; return resolve(bounds0, containingType); } final Class typeVariableOwner = (Class) genericDeclaration; // find the typeOwner in the containingType's hierarchy final LinkedList<Type> stack = new LinkedList<Type>(); // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved // by the // containingType and not the super class. if (containingType instanceof ParameterizedType) { stack.add(containingType); } Class theClass = asClass(containingType); Type genericSuperclass = theClass.getGenericSuperclass(); while (genericSuperclass != null && // true for interfaces with no superclass !theClass.equals(Object.class) && !theClass.equals(typeVariableOwner)) { stack.addFirst(genericSuperclass); theClass = asClass(genericSuperclass); genericSuperclass = theClass.getGenericSuperclass(); } int i = getTypeVariableIndex(typeVariable); Type resolved = typeVariable; for (Type t : stack) { if (t instanceof ParameterizedType) { resolved = ((ParameterizedType) t).getActualTypeArguments()[i]; if (resolved instanceof Class) return resolved; if (resolved instanceof TypeVariable) { // Need to look at the next class in the hierarchy i = getTypeVariableIndex((TypeVariable) resolved); continue; } return resolve(resolved, containingType); } } // the only way we get here is if resolved is still a TypeVariable, otherwise an // exception is thrown or a value is returned. return ((TypeVariable) resolved).getBounds()[0]; }
private void readActualTypeParametersOnDeclaringClass() { registerTypeParametersOn(clazz.getTypeParameters()); registerTypeVariablesOn(clazz.getGenericSuperclass()); for (Type genericInterface : clazz.getGenericInterfaces()) { registerTypeVariablesOn(genericInterface); } }
/** * 通过反射, 获得Class定义中声明的父类的泛型参数的类型. 如无法找到, 返回Object.class. * * <p>如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 */ public static Class getSuperClassGenricType(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]; }
@Nullable public static Type resolveVariable( TypeVariable variable, final Class classType, boolean resolveInInterfacesOnly) { final Class aClass = getRawType(classType); int index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(aClass), variable); if (index >= 0) { return variable; } final Class[] classes = ReflectionCache.getInterfaces(aClass); final Type[] genericInterfaces = ReflectionCache.getGenericInterfaces(aClass); for (int i = 0; i <= classes.length; i++) { Class anInterface; if (i < classes.length) { anInterface = classes[i]; } else { anInterface = ReflectionCache.getSuperClass(aClass); if (resolveInInterfacesOnly || anInterface == null) { continue; } } final Type resolved = resolveVariable(variable, anInterface); if (resolved instanceof Class || resolved instanceof ParameterizedType) { return resolved; } if (resolved instanceof TypeVariable) { final TypeVariable typeVariable = (TypeVariable) resolved; index = ArrayUtilRt.find(ReflectionCache.getTypeParameters(anInterface), typeVariable); if (index < 0) { LOG.error( "Cannot resolve type variable:\n" + "typeVariable = " + typeVariable + "\n" + "genericDeclaration = " + declarationToString(typeVariable.getGenericDeclaration()) + "\n" + "searching in " + declarationToString(anInterface)); } final Type type = i < genericInterfaces.length ? genericInterfaces[i] : aClass.getGenericSuperclass(); if (type instanceof Class) { return Object.class; } if (type instanceof ParameterizedType) { return getActualTypeArguments((ParameterizedType) type)[index]; } throw new AssertionError("Invalid type: " + type); } } return null; }
protected void loadClassDependencies(Class aClass) throws ClassNotFoundException { String name = aClass.getName(); if (myVisited.add(aClass)) { try { for (Method method : aClass.getDeclaredMethods()) { loadTypeDependencies(method.getGenericReturnType()); for (Type type : method.getGenericExceptionTypes()) { loadTypeDependencies(type); } for (Type type : method.getGenericParameterTypes()) { loadTypeDependencies(type); } } for (Constructor method : aClass.getDeclaredConstructors()) { for (Type type : method.getGenericExceptionTypes()) { loadTypeDependencies(type); } for (Type type : method.getGenericParameterTypes()) { loadTypeDependencies(type); } } for (Field field : aClass.getDeclaredFields()) { loadTypeDependencies(field.getGenericType()); } Type superclass = aClass.getGenericSuperclass(); if (superclass != null) { loadClassDependencies(aClass); } for (Type intf : aClass.getGenericInterfaces()) { loadTypeDependencies(intf); } aClass.getAnnotations(); Package aPackage = aClass.getPackage(); if (aPackage != null) { aPackage.getAnnotations(); } } catch (LinkageError e) { throw new ClassNotFoundException(name); } catch (TypeNotPresentException e) { throw new ClassNotFoundException(name); } } }
@Override public List<ReferenceTypeUsage> getAllAncestors(Resolver resolver) { List<ReferenceTypeUsage> ancestors = new ArrayList<>(); if (clazz.getSuperclass() != null) { ReferenceTypeUsage superTypeDefinition = toReferenceTypeUsage(clazz.getSuperclass(), clazz.getGenericSuperclass()); ancestors.add(superTypeDefinition); ancestors.addAll(superTypeDefinition.getAllAncestors(resolver)); } int i = 0; for (Class<?> interfaze : clazz.getInterfaces()) { Type genericInterfaze = clazz.getGenericInterfaces()[i]; ReferenceTypeUsage superTypeDefinition = toReferenceTypeUsage(interfaze, genericInterfaze); ancestors.add(superTypeDefinition); ancestors.addAll(superTypeDefinition.getAllAncestors(resolver)); i++; } return ancestors; }
public void configureClassNode(CompileUnit compileUnit, ClassNode classNode) { Class clazz = classNode.getTypeClass(); Field[] fields = clazz.getDeclaredFields(); for (Field f : fields) { ClassNode ret = makeClassNode(compileUnit, f.getGenericType(), f.getType()); classNode.addField(f.getName(), f.getModifiers(), ret, null); } Method[] methods = clazz.getDeclaredMethods(); for (Method m : methods) { ClassNode ret = makeClassNode(compileUnit, m.getGenericReturnType(), m.getReturnType()); Parameter[] params = makeParameters(compileUnit, m.getGenericParameterTypes(), m.getParameterTypes()); ClassNode[] exceptions = makeClassNodes(compileUnit, m.getGenericExceptionTypes(), m.getExceptionTypes()); MethodNode mn = new MethodNode(m.getName(), m.getModifiers(), ret, params, exceptions, null); setMethodDefaultValue(mn, m); setAnnotationMetaData(m.getAnnotations(), mn); mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters())); classNode.addMethod(mn); } Constructor[] constructors = clazz.getDeclaredConstructors(); for (Constructor ctor : constructors) { Parameter[] params = makeParameters(compileUnit, ctor.getGenericParameterTypes(), ctor.getParameterTypes()); ClassNode[] exceptions = makeClassNodes(compileUnit, ctor.getGenericExceptionTypes(), ctor.getExceptionTypes()); classNode.addConstructor(ctor.getModifiers(), params, exceptions, null); } Class sc = clazz.getSuperclass(); if (sc != null) classNode.setUnresolvedSuperClass( makeClassNode(compileUnit, clazz.getGenericSuperclass(), sc)); makeInterfaceTypes(compileUnit, classNode, clazz); setAnnotationMetaData(classNode.getTypeClass().getAnnotations(), classNode); PackageNode packageNode = classNode.getPackage(); if (packageNode != null) { setAnnotationMetaData(classNode.getTypeClass().getPackage().getAnnotations(), packageNode); } }
protected void _resolveBindings(Type t) { if (t == null) return; Class<?> raw; if (t instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) t; Type[] args = pt.getActualTypeArguments(); if (args != null && args.length > 0) { Class<?> rawType = (Class<?>) pt.getRawType(); TypeVariable<?>[] vars = rawType.getTypeParameters(); if (vars.length != args.length) { throw new IllegalArgumentException( "Strange parametrized type (in class " + rawType.getName() + "): number of type arguments != number of type parameters (" + args.length + " vs " + vars.length + ")"); } for (int i = 0, len = args.length; i < len; ++i) { TypeVariable<?> var = vars[i]; String name = var.getName(); if (_bindings == null) { _bindings = new LinkedHashMap<String, JavaType>(); } else { /* 24-Mar-2010, tatu: Better ensure that we do not overwrite something * collected earlier (since we descend towards super-classes): */ if (_bindings.containsKey(name)) continue; } // first: add a placeholder to prevent infinite loops _addPlaceholder(name); // then resolve type _bindings.put(name, _typeFactory._constructType(args[i], this)); } } raw = (Class<?>) pt.getRawType(); } else if (t instanceof Class<?>) { raw = (Class<?>) t; /* [JACKSON-677]: If this is an inner class then the generics are defined on the * enclosing class so we have to check there as well. We don't * need to call getEnclosingClass since anonymous classes declare * generics */ _resolveBindings(raw.getDeclaringClass()); /* 24-Mar-2010, tatu: Can not have true generics definitions, but can * have lower bounds ("<T extends BeanBase>") in declaration itself */ TypeVariable<?>[] vars = raw.getTypeParameters(); if (vars != null && vars.length > 0) { JavaType[] typeParams = null; if (_contextType != null && raw.isAssignableFrom(_contextType.getRawClass())) { typeParams = _typeFactory.findTypeParameters(_contextType, raw); } for (int i = 0; i < vars.length; i++) { TypeVariable<?> var = vars[i]; String name = var.getName(); Type varType = var.getBounds()[0]; if (varType != null) { if (_bindings == null) { _bindings = new LinkedHashMap<String, JavaType>(); } else { // and no overwriting... if (_bindings.containsKey(name)) continue; } _addPlaceholder(name); // to prevent infinite loops if (typeParams != null) { _bindings.put(name, typeParams[i]); } else { _bindings.put(name, _typeFactory._constructType(varType, this)); } } } } } else { // probably can't be any of these... so let's skip for now // if (type instanceof GenericArrayType) { // if (type instanceof TypeVariable<?>) { // if (type instanceof WildcardType) { return; } // but even if it's not a parameterized type, its super types may be: _resolveBindings(raw.getGenericSuperclass()); for (Type intType : raw.getGenericInterfaces()) { _resolveBindings(intType); } }
/** * Determines if the suspected super type is assignable from the suspected sub type. * * @param suspectedSuperType e.g. {@code GenericDAO<Pet, String>} * @param suspectedSubType e.g. {@code PetDAO extends GenericDAO<Pet,String>} * @return true if (sourceType)targetClass is a valid cast */ public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType) { final Class suspectedSuperClass = asClass(suspectedSuperType); final Class suspectedSubClass = asClass(suspectedSubType); // The raw types need to be compatible. if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass)) { return false; } // From this point we know that the raw types are assignable. // We need to figure out what the generic parameters in the targetClass are // as they pertain to the sourceType. if (suspectedSuperType instanceof WildcardType) { // ? extends Number // needs to match all the bounds (there will only be upper bounds or lower bounds for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds()) { if (!isAssignableFrom(t, suspectedSubType)) return false; } for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds()) { if (!isAssignableFrom(suspectedSubType, t)) return false; } return true; } Type curType = suspectedSubType; Class curClass; while (curType != null && !curType.equals(Object.class)) { curClass = asClass(curType); if (curClass.equals(suspectedSuperClass)) { final Type resolved = resolve(curType, suspectedSubType); if (suspectedSuperType instanceof Class) { if (resolved instanceof Class) return suspectedSuperType.equals(resolved); // They may represent the same class, but the suspectedSuperType is not parameterized. The // parameter // types default to Object so they must be a match. // e.g. Pair p = new StringLongPair(); // Pair p = new Pair<? extends Number, String> return true; } if (suspectedSuperType instanceof ParameterizedType) { if (resolved instanceof ParameterizedType) { final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments(); final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments(); if (type1Arguments.length != type2Arguments.length) return false; for (int i = 0; i < type1Arguments.length; ++i) { if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false; } return true; } } else if (suspectedSuperType instanceof GenericArrayType) { if (resolved instanceof GenericArrayType) { return isAssignableFrom( ((GenericArrayType) suspectedSuperType).getGenericComponentType(), ((GenericArrayType) resolved).getGenericComponentType()); } } return false; } final Type[] types = curClass.getGenericInterfaces(); for (Type t : types) { final Type resolved = resolve(t, suspectedSubType); if (isAssignableFrom(suspectedSuperType, resolved)) return true; } curType = curClass.getGenericSuperclass(); } return false; }
/** * Gets the actual type arguments that are used in a given implementation of a given generic base * class or interface. (Based on code copyright 2007 by Ian Robertson). * * @param base the generic base class or interface * @param implementation the type (potentially) implementing the given base class or interface * @return a list of the raw classes for the actual type arguments. */ @NotNull public static List<Class<?>> getTypeArguments( @NotNull Class<?> base, @NotNull Class<?> implementation) { Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); // first we need to resolve all supertypes up to the required base class or interface // and find the right Type for it Type type; Queue<Type> toCheck = new LinkedList<Type>(); toCheck.add(implementation); while (true) { // if we have checked everything and not found the base class we return an empty list if (toCheck.isEmpty()) return ImmutableList.of(); type = toCheck.remove(); Class<?> clazz; if (type instanceof Class) { // there is no useful information for us in raw types, so just keep going up the inheritance // chain clazz = (Class) type; if (base.isInterface()) { // if we are actually looking for the type parameters to an interface we also need to // look at all the ones implemented by the given current one toCheck.addAll(Arrays.asList(clazz.getGenericInterfaces())); } } else if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; clazz = (Class) parameterizedType.getRawType(); // for instances of ParameterizedType we extract and remember all type arguments TypeVariable<?>[] typeParameters = clazz.getTypeParameters(); Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); for (int i = 0; i < actualTypeArguments.length; i++) { resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); } } else { return ImmutableList.of(); } // we can stop if we have reached the sought for base type if (base.equals(getClass(type))) break; toCheck.add(clazz.getGenericSuperclass()); } // finally, for each actual type argument provided to baseClass, // determine (if possible) the raw class for that type argument. Type[] actualTypeArguments; if (type instanceof Class) { actualTypeArguments = ((Class) type).getTypeParameters(); } else { actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); } List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); // resolve types by chasing down type variables. for (Type baseType : actualTypeArguments) { while (resolvedTypes.containsKey(baseType)) { baseType = resolvedTypes.get(baseType); } typeArgumentsAsClasses.add(getClass(baseType)); } return typeArgumentsAsClasses; }