From: Juergen H. <jho...@us...> - 2006-04-20 18:24:37
|
Update of /cvsroot/springframework/spring/src/org/springframework/core In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12059/src/org/springframework/core Modified Files: GenericsHelper.java Log Message: correctly detect element type of collections with parameterization in superclass/interface Index: GenericsHelper.java =================================================================== RCS file: /cvsroot/springframework/spring/src/org/springframework/core/GenericsHelper.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** GenericsHelper.java 14 Mar 2006 08:02:10 -0000 1.2 --- GenericsHelper.java 20 Apr 2006 18:24:34 -0000 1.3 *************** *** 20,31 **** import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import org.springframework.util.Assert; /** ! * Helper class for determining generic types of collections and maps. * * @author Juergen Hoeller * @since 2.0 */ public abstract class GenericsHelper { --- 20,43 ---- import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; + import java.lang.reflect.WildcardType; + import java.util.Collection; + import java.util.Map; import org.springframework.util.Assert; /** ! * Helper class for determining element types of collections and maps. ! * ! * <p>Mainly intended for usage within the framework, determining the ! * target type of values to be added to a collection or map ! * (to be able to attempt type conversion if appropriate). ! * ! * <p>Only usable on Java 5. Use an appropriate JdkVersion check before ! * calling this class, if a fallback for JDK 1.3/1.4 is desirable. * * @author Juergen Hoeller * @since 2.0 + * @see org.springframework.beans.BeanWrapperImpl + * @see JdkVersion */ public abstract class GenericsHelper { *************** *** 37,41 **** */ public static Class getCollectionParameterType(MethodParameter methodParam) { ! return getGenericParameterType(methodParam, 0); } --- 49,53 ---- */ public static Class getCollectionParameterType(MethodParameter methodParam) { ! return getGenericParameterType(methodParam, Collection.class, 0); } *************** *** 46,50 **** */ public static Class getMapKeyParameterType(MethodParameter methodParam) { ! return getGenericParameterType(methodParam, 0); } --- 58,62 ---- */ public static Class getMapKeyParameterType(MethodParameter methodParam) { ! return getGenericParameterType(methodParam, Map.class, 0); } *************** *** 55,59 **** */ public static Class getMapValueParameterType(MethodParameter methodParam) { ! return getGenericParameterType(methodParam, 1); } --- 67,71 ---- */ public static Class getMapValueParameterType(MethodParameter methodParam) { ! return getGenericParameterType(methodParam, Map.class, 1); } *************** *** 64,68 **** */ public static Class getCollectionReturnType(Method method) { ! return getGenericReturnType(method, 0); } --- 76,80 ---- */ public static Class getCollectionReturnType(Method method) { ! return getGenericReturnType(method, Collection.class, 0); } *************** *** 73,77 **** */ public static Class getMapKeyReturnType(Method method) { ! return getGenericReturnType(method, 0); } --- 85,89 ---- */ public static Class getMapKeyReturnType(Method method) { ! return getGenericReturnType(method, Map.class, 0); } *************** *** 82,86 **** */ public static Class getMapValueReturnType(Method method) { ! return getGenericReturnType(method, 1); } --- 94,98 ---- */ public static Class getMapValueReturnType(Method method) { ! return getGenericReturnType(method, Map.class, 1); } *************** *** 89,105 **** * Extract the generic parameter type from the given method or constructor. * @param methodParam the method parameter specification * @param typeIndex the index of the type (e.g. 0 for Collections, * 0 for Map keys, 1 for Map values) * @return the generic type, or <code>null</code> if none */ ! private static Class getGenericParameterType(MethodParameter methodParam, int typeIndex) { Assert.notNull(methodParam, "MethodParameter must not be null"); if (methodParam.getConstructor() != null) { ! return extractType( ! methodParam.getConstructor().getGenericParameterTypes()[methodParam.getParameterIndex()], typeIndex); } else { ! return extractType( ! methodParam.getMethod().getGenericParameterTypes()[methodParam.getParameterIndex()], typeIndex); } } --- 101,117 ---- * Extract the generic parameter type from the given method or constructor. * @param methodParam the method parameter specification + * @param source the source class/interface defining the generic parameter types * @param typeIndex the index of the type (e.g. 0 for Collections, * 0 for Map keys, 1 for Map values) * @return the generic type, or <code>null</code> if none */ ! private static Class getGenericParameterType(MethodParameter methodParam, Class source, int typeIndex) { Assert.notNull(methodParam, "MethodParameter must not be null"); + int idx = methodParam.getParameterIndex(); if (methodParam.getConstructor() != null) { ! return extractType(methodParam.getConstructor().getGenericParameterTypes()[idx], source, typeIndex); } else { ! return extractType(methodParam.getMethod().getGenericParameterTypes()[idx], source, typeIndex); } } *************** *** 108,120 **** * Extract the generic return type from the given method. * @param method the method to check the return type for * @param typeIndex the index of the type (e.g. 0 for Collections, * 0 for Map keys, 1 for Map values) * @return the generic type, or <code>null</code> if none */ ! private static Class getGenericReturnType(Method method, int typeIndex) { Assert.notNull(method, "Method must not be null"); ! return extractType(method.getGenericReturnType(), typeIndex); } /** * Extract the generic type from the given Type object. --- 120,134 ---- * Extract the generic return type from the given method. * @param method the method to check the return type for + * @param source the source class/interface defining the generic parameter types * @param typeIndex the index of the type (e.g. 0 for Collections, * 0 for Map keys, 1 for Map values) * @return the generic type, or <code>null</code> if none */ ! private static Class getGenericReturnType(Method method, Class source, int typeIndex) { Assert.notNull(method, "Method must not be null"); ! return extractType(method.getGenericReturnType(), source, typeIndex); } + /** * Extract the generic type from the given Type object. *************** *** 123,131 **** * @return the generic type as Class, or <code>null</code> if none */ ! private static Class extractType(Type type, int typeIndex) { if (type instanceof ParameterizedType) { ! Type[] paramTypes = ((ParameterizedType) type).getActualTypeArguments(); ! if (paramTypes[typeIndex] instanceof Class) { ! return (Class) paramTypes[typeIndex]; } } --- 137,209 ---- * @return the generic type as Class, or <code>null</code> if none */ ! private static Class extractType(Type type, Class source, int typeIndex) { if (type instanceof ParameterizedType) { ! return extractTypeFromParameterizedType((ParameterizedType) type, source, typeIndex); ! } ! if (type instanceof Class) { ! return extractTypeFromClass((Class) type, source, typeIndex); ! } ! return null; ! } ! ! /** ! * Extract the generic type from the given ParameterizedType object. ! * @param ptype the ParameterizedType to check ! * @param typeIndex the index of the actual type argument ! * @return the generic type as Class, or <code>null</code> if none ! */ ! private static Class extractTypeFromParameterizedType(ParameterizedType ptype, Class source, int typeIndex) { ! if (!(ptype.getRawType() instanceof Class)) { ! return null; ! } ! Class rawType = (Class) ptype.getRawType(); ! if (!source.isAssignableFrom(rawType)) { ! return null; ! } ! Class fromSuperclassOrInterface = extractType(rawType, source, typeIndex); ! if (fromSuperclassOrInterface != null) { ! return fromSuperclassOrInterface; ! } ! Type[] paramTypes = ptype.getActualTypeArguments(); ! if (paramTypes == null || typeIndex >= paramTypes.length) { ! return null; ! } ! Type paramType = paramTypes[typeIndex]; ! if (paramType instanceof WildcardType) { ! Type[] lowerBounds = ((WildcardType) paramType).getLowerBounds(); ! if (lowerBounds != null && lowerBounds.length > 0) { ! paramType = lowerBounds[0]; ! } ! } ! if (paramType instanceof ParameterizedType) { ! paramType = ((ParameterizedType) paramType).getRawType(); ! } ! if (paramType instanceof Class) { ! return (Class) paramType; ! } ! return null; ! } ! ! /** ! * Extract the generic type from the given Class object. ! * @param clazz the Class to check ! * @param typeIndex the index of the actual type argument ! * @return the generic type as Class, or <code>null</code> if none ! */ ! private static Class extractTypeFromClass(Class clazz, Class source, int typeIndex) { ! if (clazz.getSuperclass() != null && source.isAssignableFrom(clazz.getSuperclass())) { ! return extractType(clazz.getGenericSuperclass(), source, typeIndex); ! } ! Type[] ifcs = clazz.getGenericInterfaces(); ! if (ifcs != null) { ! for (int i = 0; i < ifcs.length; i++) { ! Type ifc = ifcs[i]; ! Type rawType = ifc; ! if (ifc instanceof ParameterizedType) { ! rawType = ((ParameterizedType) ifc).getRawType(); ! } ! if (rawType instanceof Class && source.isAssignableFrom((Class) rawType)) { ! return extractType(ifc, source, typeIndex); ! } } } |