1 16 17 package org.springframework.core; 18 19 import java.lang.reflect.GenericArrayType ; 20 import java.lang.reflect.Method ; 21 import java.lang.reflect.ParameterizedType ; 22 import java.lang.reflect.Type ; 23 import java.lang.reflect.TypeVariable ; 24 import java.util.ArrayList ; 25 import java.util.HashMap ; 26 import java.util.List ; 27 import java.util.Map ; 28 29 import org.springframework.util.Assert; 30 import org.springframework.util.ClassUtils; 31 import org.springframework.util.ReflectionUtils; 32 33 55 public abstract class BridgeMethodResolver { 56 57 64 public static Method findBridgedMethod(Method bridgeMethod) { 65 Assert.notNull(bridgeMethod, "Method must not be null"); 66 67 if (!bridgeMethod.isBridge()) { 68 return bridgeMethod; 69 } 70 71 List candidateMethods = new ArrayList (); 73 Method [] methods = ReflectionUtils.getAllDeclaredMethods(bridgeMethod.getDeclaringClass()); 74 for (int i = 0; i < methods.length; i++) { 75 Method candidateMethod = methods[i]; 76 if (isBridgedCandidateFor(candidateMethod, bridgeMethod)) { 77 candidateMethods.add(candidateMethod); 78 } 79 } 80 81 Method result; 82 if (candidateMethods.size() == 1) { 84 result = (Method ) candidateMethods.get(0); 85 } 86 else { 87 result = searchCandidates(candidateMethods, bridgeMethod); 88 } 89 90 if (result == null) { 91 throw new IllegalStateException ( 92 "Unable to locate bridged method for bridge method '" + bridgeMethod + "'"); 93 } 94 95 return result; 96 } 97 98 104 private static Method searchCandidates(List candidateMethods, Method bridgeMethod) { 105 Map typeParameterMap = createTypeVariableMap(bridgeMethod.getDeclaringClass()); 106 for (int i = 0; i < candidateMethods.size(); i++) { 107 Method candidateMethod = (Method ) candidateMethods.get(i); 108 if (isBridgeMethodFor(bridgeMethod, candidateMethod, typeParameterMap)) { 109 return candidateMethod; 110 } 111 } 112 return null; 113 } 114 115 121 private static boolean isBridgedCandidateFor(Method candidateMethod, Method bridgeMethod) { 122 return (!candidateMethod.isBridge() && !candidateMethod.equals(bridgeMethod) && 123 candidateMethod.getName().equals(bridgeMethod.getName()) && 124 candidateMethod.getParameterTypes().length == bridgeMethod.getParameterTypes().length); 125 } 126 127 131 static boolean isBridgeMethodFor(Method bridgeMethod, Method candidateMethod, Map typeVariableMap) { 132 if (isResolvedTypeMatch(candidateMethod, bridgeMethod, typeVariableMap)) { 133 return true; 134 } 135 Method method = findGenericDeclaration(bridgeMethod); 136 return (method != null ? isResolvedTypeMatch(method, candidateMethod, typeVariableMap) : false); 137 } 138 139 144 private static Method findGenericDeclaration(Method bridgeMethod) { 145 Class superclass = bridgeMethod.getDeclaringClass().getSuperclass(); 147 while (!Object .class.equals(superclass)) { 148 Method method = searchForMatch(superclass, bridgeMethod); 149 if (method != null && !method.isBridge()) { 150 return method; 151 } 152 superclass = superclass.getSuperclass(); 153 } 154 155 Class [] interfaces = ClassUtils.getAllInterfacesForClass(bridgeMethod.getDeclaringClass()); 157 for (int i = 0; i < interfaces.length; i++) { 158 Class anInterface = interfaces[i]; 159 Method method = searchForMatch(anInterface, bridgeMethod); 160 if (method != null && !method.isBridge()) { 161 return method; 162 } 163 } 164 165 return null; 166 } 167 168 174 private static boolean isResolvedTypeMatch(Method genericMethod, Method candidateMethod, Map typeVariableMap) { 175 Type [] genericParameters = genericMethod.getGenericParameterTypes(); 176 Class [] candidateParameters = candidateMethod.getParameterTypes(); 177 if (genericParameters.length != candidateParameters.length) { 178 return false; 179 } 180 for (int i = 0; i < genericParameters.length; i++) { 181 Type genericParameter = genericParameters[i]; 182 Class candidateParameter = candidateParameters[i]; 183 if (genericParameter instanceof GenericArrayType && candidateParameter.isArray()) { 184 if (!candidateParameter.getComponentType().equals( 186 getRawType(((GenericArrayType ) genericParameter).getGenericComponentType(), typeVariableMap))) { 187 return false; 188 } 189 } 190 else { 191 if (!candidateParameter.equals(getRawType(genericParameter, typeVariableMap))) { 193 return false; 194 } 195 } 196 } 197 return true; 198 } 199 200 203 private static Type getRawType(Type genericType, Map typeVariableMap) { 204 if (genericType instanceof TypeVariable ) { 205 TypeVariable tv = (TypeVariable ) genericType; 206 return (Type ) typeVariableMap.get(tv.getName()); 207 } 208 else if (genericType instanceof ParameterizedType ) { 209 return ((ParameterizedType ) genericType).getRawType(); 210 } 211 else { 212 return genericType; 213 } 214 } 215 216 221 private static Method searchForMatch(Class type, Method bridgeMethod) { 222 return ReflectionUtils.findMethod(type, bridgeMethod.getName(), bridgeMethod.getParameterTypes()); 223 } 224 225 230 static Map createTypeVariableMap(Class cls) { 231 Map typeVariableMap = new HashMap (); 232 233 extractTypeVariablesFromGenericInterfaces(cls.getGenericInterfaces(), typeVariableMap); 235 236 Type genericType = cls.getGenericSuperclass(); 238 Class type = cls.getSuperclass(); 239 while (!Object .class.equals(type)) { 240 if (genericType instanceof ParameterizedType ) { 241 ParameterizedType pt = (ParameterizedType ) genericType; 242 populateTypeMapFromParameterizedType(typeVariableMap, pt); 243 } 244 extractTypeVariablesFromGenericInterfaces(type.getGenericInterfaces(), typeVariableMap); 245 genericType = type.getGenericSuperclass(); 246 type = type.getSuperclass(); 247 } 248 249 type = cls; 251 while (type.isMemberClass()) { 252 genericType = type.getGenericSuperclass(); 253 if (genericType instanceof ParameterizedType ) { 254 ParameterizedType pt = (ParameterizedType ) genericType; 255 populateTypeMapFromParameterizedType(typeVariableMap, pt); 256 } 257 type = type.getEnclosingClass(); 258 } 259 260 return typeVariableMap; 261 } 262 263 private static void extractTypeVariablesFromGenericInterfaces(Type [] genericInterfaces, Map typeVariableMap) { 264 for (int i = 0; i < genericInterfaces.length; i++) { 265 Type genericInterface = genericInterfaces[i]; 266 if (genericInterface instanceof ParameterizedType ) { 267 ParameterizedType pt = (ParameterizedType ) genericInterface; 268 populateTypeMapFromParameterizedType(typeVariableMap, pt); 269 } 270 else if (genericInterface instanceof Class ) { 271 extractTypeVariablesFromGenericInterfaces(((Class )genericInterface).getGenericInterfaces(), typeVariableMap); 272 } 273 } 274 } 275 276 277 293 private static void populateTypeMapFromParameterizedType(Map typeVariableMap, ParameterizedType type) { 294 Type [] actualTypeArguments = type.getActualTypeArguments(); 295 TypeVariable [] typeVariables = ((Class ) type.getRawType()).getTypeParameters(); 296 for (int i = 0; i < actualTypeArguments.length; i++) { 297 Type actualTypeArgument = actualTypeArguments[i]; 298 if (actualTypeArgument instanceof Class ) { 299 typeVariableMap.put(typeVariables[i].getName(), (Class ) actualTypeArgument); 300 } 301 else if (actualTypeArgument instanceof ParameterizedType ) { 302 typeVariableMap.put(typeVariables[i].getName(), ((ParameterizedType )actualTypeArgument).getRawType()); 303 } 304 else if (actualTypeArgument instanceof TypeVariable ) { 305 TypeVariable typeVariableArgument = (TypeVariable ) actualTypeArgument; 308 Class boundClass = extractClassTypeVariable(typeVariableArgument); 309 if (boundClass != null) { 310 typeVariableMap.put(typeVariables[i].getName(), boundClass); 311 } 312 } 313 } 314 } 315 316 319 private static Class extractClassTypeVariable(TypeVariable typeVariable) { 320 Type [] bounds = typeVariable.getBounds(); 321 Type result = null; 322 if (bounds.length > 0) { 323 Type bound = bounds[0]; 324 if (bound instanceof ParameterizedType ) { 325 result = ((ParameterizedType ) bound).getRawType(); 326 } 327 else if (bound instanceof Class ) { 328 result = bound; 329 } 330 else if (bound instanceof TypeVariable ) { 331 result = extractClassTypeVariable((TypeVariable )bound); 332 } 333 } 334 return (result instanceof Class ? (Class ) result : null); 335 } 336 337 } 338 | Popular Tags |