1 16 17 package org.springframework.core; 18 19 import java.lang.reflect.Array ; 20 import java.lang.reflect.GenericArrayType ; 21 import java.lang.reflect.Method ; 22 import java.lang.reflect.ParameterizedType ; 23 import java.lang.reflect.Type ; 24 import java.lang.reflect.WildcardType ; 25 import java.util.Collection ; 26 import java.util.Map ; 27 28 import org.springframework.util.Assert; 29 30 45 public abstract class GenericCollectionTypeResolver { 46 47 53 public static Class getCollectionType(Class collectionClass) { 54 return extractTypeFromClass(collectionClass, Collection .class, 0); 55 } 56 57 63 public static Class getMapKeyType(Class mapClass) { 64 return extractTypeFromClass(mapClass, Map .class, 0); 65 } 66 67 73 public static Class getMapValueType(Class mapClass) { 74 return extractTypeFromClass(mapClass, Map .class, 1); 75 } 76 77 82 public static Class getCollectionParameterType(MethodParameter methodParam) { 83 return getGenericParameterType(methodParam, Collection .class, 0); 84 } 85 86 91 public static Class getMapKeyParameterType(MethodParameter methodParam) { 92 return getGenericParameterType(methodParam, Map .class, 0); 93 } 94 95 100 public static Class getMapValueParameterType(MethodParameter methodParam) { 101 return getGenericParameterType(methodParam, Map .class, 1); 102 } 103 104 109 public static Class getCollectionReturnType(Method method) { 110 return getGenericReturnType(method, Collection .class, 0, 1); 111 } 112 113 123 public static Class getCollectionReturnType(Method method, int nestingLevel) { 124 return getGenericReturnType(method, Collection .class, 0, nestingLevel); 125 } 126 127 132 public static Class getMapKeyReturnType(Method method) { 133 return getGenericReturnType(method, Map .class, 0, 1); 134 } 135 136 144 public static Class getMapKeyReturnType(Method method, int nestingLevel) { 145 return getGenericReturnType(method, Map .class, 0, nestingLevel); 146 } 147 148 153 public static Class getMapValueReturnType(Method method) { 154 return getGenericReturnType(method, Map .class, 1, 1); 155 } 156 157 165 public static Class getMapValueReturnType(Method method, int nestingLevel) { 166 return getGenericReturnType(method, Map .class, 1, nestingLevel); 167 } 168 169 170 178 private static Class getGenericParameterType(MethodParameter methodParam, Class source, int typeIndex) { 179 Assert.notNull(methodParam, "MethodParameter must not be null"); 180 return extractType(methodParam, getTargetType(methodParam), source, typeIndex, methodParam.getNestingLevel()); 181 } 182 183 188 private static Type getTargetType(MethodParameter methodParam) { 189 if (methodParam.getConstructor() != null) { 190 return methodParam.getConstructor().getGenericParameterTypes()[methodParam.getParameterIndex()]; 191 } 192 else { 193 if (methodParam.getParameterIndex() >= 0) { 194 return methodParam.getMethod().getGenericParameterTypes()[methodParam.getParameterIndex()]; 195 } 196 else { 197 return methodParam.getMethod().getGenericReturnType(); 198 } 199 } 200 } 201 202 211 private static Class getGenericReturnType(Method method, Class source, int typeIndex, int nestingLevel) { 212 Assert.notNull(method, "Method must not be null"); 213 return extractType(null, method.getGenericReturnType(), source, typeIndex, nestingLevel); 214 } 215 216 225 private static Class extractType( 226 MethodParameter methodParam, Type type, Class source, int typeIndex, int nestingLevel) { 227 228 Assert.isTrue(typeIndex >= 0, "Type index must be >=1"); 229 Assert.isTrue(nestingLevel >= 0, "Nesting level must be >=1"); 230 if (type instanceof ParameterizedType ) { 231 return extractTypeFromParameterizedType( 232 methodParam, (ParameterizedType ) type, source, typeIndex, nestingLevel); 233 } 234 if (type instanceof Class ) { 235 return extractTypeFromClass(methodParam, (Class ) type, source, typeIndex, nestingLevel); 236 } 237 return null; 238 } 239 240 249 private static Class extractTypeFromParameterizedType( 250 MethodParameter methodParam, ParameterizedType ptype, Class source, int typeIndex, int nestingLevel) { 251 252 if (!(ptype.getRawType() instanceof Class )) { 253 return null; 254 } 255 Class rawType = (Class ) ptype.getRawType(); 256 Type [] paramTypes = ptype.getActualTypeArguments(); 257 if (nestingLevel > 1) { 258 Integer currentTypeIndex = 259 (methodParam != null ? methodParam.getTypeIndexForLevel(nestingLevel) : null); 260 int indexToUse = (currentTypeIndex != null ? currentTypeIndex.intValue() : paramTypes.length - 1); 262 Type paramType = paramTypes[indexToUse]; 263 return extractType(methodParam, paramType, source, typeIndex, nestingLevel - 1); 264 } 265 if (source != null && !source.isAssignableFrom(rawType)) { 266 return null; 267 } 268 Class fromSuperclassOrInterface = 269 extractTypeFromClass(methodParam, rawType, source, typeIndex, nestingLevel); 270 if (fromSuperclassOrInterface != null) { 271 return fromSuperclassOrInterface; 272 } 273 if (paramTypes == null || typeIndex >= paramTypes.length) { 274 return null; 275 } 276 Type paramType = paramTypes[typeIndex]; 277 if (paramType instanceof WildcardType ) { 278 Type [] lowerBounds = ((WildcardType ) paramType).getLowerBounds(); 279 if (lowerBounds != null && lowerBounds.length > 0) { 280 paramType = lowerBounds[0]; 281 } 282 } 283 if (paramType instanceof ParameterizedType ) { 284 paramType = ((ParameterizedType ) paramType).getRawType(); 285 } 286 if (paramType instanceof GenericArrayType ) { 287 Type compType = ((GenericArrayType ) paramType).getGenericComponentType(); 289 if (compType instanceof Class ) { 290 return Array.newInstance((Class ) compType, 0).getClass(); 291 } 292 } 293 else if (paramType instanceof Class ) { 294 return (Class ) paramType; 296 } 297 return null; 298 } 299 300 307 private static Class extractTypeFromClass(Class clazz, Class source, int typeIndex) { 308 return extractTypeFromClass(null, clazz, source, typeIndex, 1); 309 } 310 311 320 private static Class extractTypeFromClass( 321 MethodParameter methodParam, Class clazz, Class source, int typeIndex, int nestingLevel) { 322 323 Assert.notNull(clazz, "Class must not be null"); 324 if (clazz.getSuperclass() != null && isIntrospectionCandidate(clazz.getSuperclass())) { 325 return extractType(methodParam, clazz.getGenericSuperclass(), source, typeIndex, nestingLevel); 326 } 327 Type [] ifcs = clazz.getGenericInterfaces(); 328 if (ifcs != null) { 329 for (int i = 0; i < ifcs.length; i++) { 330 Type ifc = ifcs[i]; 331 Type rawType = ifc; 332 if (ifc instanceof ParameterizedType ) { 333 rawType = ((ParameterizedType ) ifc).getRawType(); 334 } 335 if (rawType instanceof Class && isIntrospectionCandidate((Class ) rawType)) { 336 return extractType(methodParam, ifc, source, typeIndex, nestingLevel); 337 } 338 } 339 } 340 return null; 341 } 342 343 349 private static boolean isIntrospectionCandidate(Class clazz) { 350 return (Collection .class.isAssignableFrom(clazz) || Map .class.isAssignableFrom(clazz)); 351 } 352 353 } 354 | Popular Tags |