2121import  java .lang .reflect .Type ;
2222import  java .lang .reflect .TypeVariable ;
2323import  java .lang .reflect .WildcardType ;
24- import  java .util .Collections ;
25- import  java .util .HashMap ;
26- import  java .util .Map ;
2724
2825import  org .springframework .util .Assert ;
29- import  org .springframework .util .ConcurrentReferenceHashMap ;
3026
3127/** 
3228 * Helper class for resolving generic types against type variables. 
4238 */ 
4339public  abstract  class  GenericTypeResolver  {
4440
45- 	/** Cache from Class to TypeVariable Map */ 
46- 	@ SuppressWarnings ("rawtypes" )
47- 	private  static  final  Map <Class <?>, Map <TypeVariable , Type >> typeVariableCache  =
48- 			new  ConcurrentReferenceHashMap <>();
49- 
50- 
51- 	/** 
52- 	 * Determine the target type for the given parameter specification. 
53- 	 * @param methodParameter the method parameter specification 
54- 	 * @return the corresponding generic parameter type 
55- 	 * @deprecated as of Spring 4.0, use {@link MethodParameter#getGenericParameterType()} 
56- 	 */ 
57- 	@ Deprecated 
58- 	public  static  Type  getTargetType (MethodParameter  methodParameter ) {
59- 		Assert .notNull (methodParameter , "MethodParameter must not be null" );
60- 		return  methodParameter .getGenericParameterType ();
61- 	}
62- 
6341	/** 
6442	 * Determine the target type for the given generic parameter type. 
6543	 * @param methodParameter the method parameter specification 
@@ -80,114 +58,13 @@ public static Class<?> resolveParameterType(MethodParameter methodParameter, Cla
8058	 * @param method the method to introspect 
8159	 * @param clazz the class to resolve type variables against 
8260	 * @return the corresponding generic parameter or return type 
83- 	 * @see #resolveReturnTypeForGenericMethod 
8461	 */ 
8562	public  static  Class <?> resolveReturnType (Method  method , Class <?> clazz ) {
8663		Assert .notNull (method , "Method must not be null" );
8764		Assert .notNull (clazz , "Class must not be null" );
8865		return  ResolvableType .forMethodReturnType (method , clazz ).resolve (method .getReturnType ());
8966	}
9067
91- 	/** 
92- 	 * Determine the target type for the generic return type of the given 
93- 	 * <em>generic method</em>, where formal type variables are declared on 
94- 	 * the given method itself. 
95- 	 * <p>For example, given a factory method with the following signature, 
96- 	 * if {@code resolveReturnTypeForGenericMethod()} is invoked with the reflected 
97- 	 * method for {@code creatProxy()} and an {@code Object[]} array containing 
98- 	 * {@code MyService.class}, {@code resolveReturnTypeForGenericMethod()} will 
99- 	 * infer that the target return type is {@code MyService}. 
100- 	 * <pre class="code">{@code public static <T> T createProxy(Class<T> clazz)}</pre> 
101- 	 * <h4>Possible Return Values</h4> 
102- 	 * <ul> 
103- 	 * <li>the target return type, if it can be inferred</li> 
104- 	 * <li>the {@linkplain Method#getReturnType() standard return type}, if 
105- 	 * the given {@code method} does not declare any {@linkplain 
106- 	 * Method#getTypeParameters() formal type variables}</li> 
107- 	 * <li>the {@linkplain Method#getReturnType() standard return type}, if the 
108- 	 * target return type cannot be inferred (e.g., due to type erasure)</li> 
109- 	 * <li>{@code null}, if the length of the given arguments array is shorter 
110- 	 * than the length of the {@linkplain 
111- 	 * Method#getGenericParameterTypes() formal argument list} for the given 
112- 	 * method</li> 
113- 	 * </ul> 
114- 	 * @param method the method to introspect, never {@code null} 
115- 	 * @param args the arguments that will be supplied to the method when it is 
116- 	 * invoked (never {@code null}) 
117- 	 * @param classLoader the ClassLoader to resolve class names against, if necessary 
118- 	 * (may be {@code null}) 
119- 	 * @return the resolved target return type, the standard return type, or {@code null} 
120- 	 * @since 3.2.5 
121- 	 * @see #resolveReturnType 
122- 	 */ 
123- 	public  static  Class <?> resolveReturnTypeForGenericMethod (Method  method , Object [] args , ClassLoader  classLoader ) {
124- 		Assert .notNull (method , "Method must not be null" );
125- 		Assert .notNull (args , "Argument array must not be null" );
126- 
127- 		TypeVariable <Method >[] declaredTypeVariables  = method .getTypeParameters ();
128- 		Type  genericReturnType  = method .getGenericReturnType ();
129- 		Type [] methodArgumentTypes  = method .getGenericParameterTypes ();
130- 
131- 		// No declared type variables to inspect, so just return the standard return type. 
132- 		if  (declaredTypeVariables .length  == 0 ) {
133- 			return  method .getReturnType ();
134- 		}
135- 
136- 		// The supplied argument list is too short for the method's signature, so 
137- 		// return null, since such a method invocation would fail. 
138- 		if  (args .length  < methodArgumentTypes .length ) {
139- 			return  null ;
140- 		}
141- 
142- 		// Ensure that the type variable (e.g., T) is declared directly on the method 
143- 		// itself (e.g., via <T>), not on the enclosing class or interface. 
144- 		boolean  locallyDeclaredTypeVariableMatchesReturnType  = false ;
145- 		for  (TypeVariable <Method > currentTypeVariable  : declaredTypeVariables ) {
146- 			if  (currentTypeVariable .equals (genericReturnType )) {
147- 				locallyDeclaredTypeVariableMatchesReturnType  = true ;
148- 				break ;
149- 			}
150- 		}
151- 
152- 		if  (locallyDeclaredTypeVariableMatchesReturnType ) {
153- 			for  (int  i  = 0 ; i  < methodArgumentTypes .length ; i ++) {
154- 				Type  currentMethodArgumentType  = methodArgumentTypes [i ];
155- 				if  (currentMethodArgumentType .equals (genericReturnType )) {
156- 					return  args [i ].getClass ();
157- 				}
158- 				if  (currentMethodArgumentType  instanceof  ParameterizedType ) {
159- 					ParameterizedType  parameterizedType  = (ParameterizedType ) currentMethodArgumentType ;
160- 					Type [] actualTypeArguments  = parameterizedType .getActualTypeArguments ();
161- 					for  (Type  typeArg  : actualTypeArguments ) {
162- 						if  (typeArg .equals (genericReturnType )) {
163- 							Object  arg  = args [i ];
164- 							if  (arg  instanceof  Class ) {
165- 								return  (Class <?>) arg ;
166- 							}
167- 							else  if  (arg  instanceof  String  && classLoader  != null ) {
168- 								try  {
169- 									return  classLoader .loadClass ((String ) arg );
170- 								}
171- 								catch  (ClassNotFoundException  ex ) {
172- 									throw  new  IllegalStateException (
173- 											"Could not resolve specific class name argument ["  + arg  + "]" , ex );
174- 								}
175- 							}
176- 							else  {
177- 								// Consider adding logic to determine the class of the typeArg, if possible. 
178- 								// For now, just fall back... 
179- 								return  method .getReturnType ();
180- 							}
181- 						}
182- 					}
183- 				}
184- 			}
185- 		}
186- 
187- 		// Fall back... 
188- 		return  method .getReturnType ();
189- 	}
190- 
19168	/** 
19269	 * Resolve the single type argument of the given generic interface against the given 
19370	 * target method which is assumed to return the given interface or an implementation 
@@ -248,81 +125,75 @@ public static Class<?>[] resolveTypeArguments(Class<?> clazz, Class<?> genericIf
248125	}
249126
250127	/** 
251- 	 * Resolve the specified generic type against the given TypeVariable map. 
252- 	 * @param genericType the generic type to resolve 
253- 	 * @param map the TypeVariable Map to resolved against 
254- 	 * @return the type if it resolves to a Class, or {@code Object.class} otherwise 
255- 	 * @deprecated as of Spring 4.0 in favor of {@link ResolvableType} 
128+ 	 * Resolve the given generic type against the given context class, 
129+ 	 * substituting type variables as far as possible. 
130+ 	 * @param genericType the (potentially) generic type 
131+ 	 * @param contextClass a context class for the target type, for example a class 
132+ 	 * in which the target type appears in a method signature (can be {@code null}) 
133+ 	 * @return the resolved type (possibly the given generic type as-is) 
134+ 	 * @since 5.0 
256135	 */ 
257- 	@ Deprecated 
258- 	@ SuppressWarnings ("rawtypes" )
259- 	public  static  Class <?> resolveType (Type  genericType , Map <TypeVariable , Type > map ) {
260- 		return  ResolvableType .forType (genericType , new  TypeVariableMapVariableResolver (map )).resolve (Object .class );
261- 	}
262- 
263- 	/** 
264- 	 * Build a mapping of {@link TypeVariable#getName TypeVariable names} to 
265- 	 * {@link Class concrete classes} for the specified {@link Class}. Searches 
266- 	 * all super types, enclosing types and interfaces. 
267- 	 * @deprecated as of Spring 4.0 in favor of {@link ResolvableType} 
268- 	 */ 
269- 	@ Deprecated 
270- 	@ SuppressWarnings ("rawtypes" )
271- 	public  static  Map <TypeVariable , Type > getTypeVariableMap (Class <?> clazz ) {
272- 		Map <TypeVariable , Type > typeVariableMap  = typeVariableCache .get (clazz );
273- 		if  (typeVariableMap  == null ) {
274- 			typeVariableMap  = new  HashMap <>();
275- 			buildTypeVariableMap (ResolvableType .forClass (clazz ), typeVariableMap );
276- 			typeVariableCache .put (clazz , Collections .unmodifiableMap (typeVariableMap ));
277- 		}
278- 		return  typeVariableMap ;
279- 	}
280- 
281- 	@ SuppressWarnings ("rawtypes" )
282- 	private  static  void  buildTypeVariableMap (ResolvableType  type , Map <TypeVariable , Type > typeVariableMap ) {
283- 		if  (type  != ResolvableType .NONE ) {
284- 			if  (type .getType () instanceof  ParameterizedType ) {
285- 				TypeVariable <?>[] variables  = type .resolve ().getTypeParameters ();
286- 				for  (int  i  = 0 ; i  < variables .length ; i ++) {
287- 					ResolvableType  generic  = type .getGeneric (i );
288- 					while  (generic .getType () instanceof  TypeVariable <?>) {
289- 						generic  = generic .resolveType ();
290- 					}
291- 					if  (generic  != ResolvableType .NONE ) {
292- 						typeVariableMap .put (variables [i ], generic .getType ());
293- 					}
136+ 	public  static  Type  resolveType (Type  genericType , Class <?> contextClass ) {
137+ 		if  (contextClass  != null ) {
138+ 			if  (genericType  instanceof  TypeVariable ) {
139+ 				ResolvableType  resolvedTypeVariable  = resolveVariable (
140+ 						(TypeVariable <?>) genericType , ResolvableType .forClass (contextClass ));
141+ 				if  (resolvedTypeVariable  != ResolvableType .NONE ) {
142+ 					return  resolvedTypeVariable .resolve ();
294143				}
295144			}
296- 			buildTypeVariableMap (type .getSuperType (), typeVariableMap );
297- 			for  (ResolvableType  interfaceType  : type .getInterfaces ()) {
298- 				buildTypeVariableMap (interfaceType , typeVariableMap );
299- 			}
300- 			if  (type .resolve ().isMemberClass ()) {
301- 				buildTypeVariableMap (ResolvableType .forClass (type .resolve ().getEnclosingClass ()), typeVariableMap );
145+ 			else  if  (genericType  instanceof  ParameterizedType ) {
146+ 				ResolvableType  resolvedType  = ResolvableType .forType (genericType );
147+ 				if  (resolvedType .hasUnresolvableGenerics ()) {
148+ 					ParameterizedType  parameterizedType  = (ParameterizedType ) genericType ;
149+ 					Class <?>[] generics  = new  Class <?>[parameterizedType .getActualTypeArguments ().length ];
150+ 					Type [] typeArguments  = parameterizedType .getActualTypeArguments ();
151+ 					for  (int  i  = 0 ; i  < typeArguments .length ; i ++) {
152+ 						Type  typeArgument  = typeArguments [i ];
153+ 						if  (typeArgument  instanceof  TypeVariable ) {
154+ 							ResolvableType  resolvedTypeArgument  = resolveVariable (
155+ 									(TypeVariable <?>) typeArgument , ResolvableType .forClass (contextClass ));
156+ 							if  (resolvedTypeArgument  != ResolvableType .NONE ) {
157+ 								generics [i ] = resolvedTypeArgument .resolve ();
158+ 							}
159+ 							else  {
160+ 								generics [i ] = ResolvableType .forType (typeArgument ).resolve ();
161+ 							}
162+ 						}
163+ 						else  {
164+ 							generics [i ] = ResolvableType .forType (typeArgument ).resolve ();
165+ 						}
166+ 					}
167+ 					return  ResolvableType .forClassWithGenerics (resolvedType .getRawClass (), generics ).getType ();
168+ 				}
302169			}
303170		}
171+ 		return  genericType ;
304172	}
305173
306- 
307- 	@ SuppressWarnings ({"serial" , "rawtypes" })
308- 	private  static  class  TypeVariableMapVariableResolver  implements  ResolvableType .VariableResolver  {
309- 
310- 		private  final  Map <TypeVariable , Type > typeVariableMap ;
311- 
312- 		public  TypeVariableMapVariableResolver (Map <TypeVariable , Type > typeVariableMap ) {
313- 			this .typeVariableMap  = typeVariableMap ;
174+ 	private  static  ResolvableType  resolveVariable (TypeVariable <?> typeVariable , ResolvableType  contextType ) {
175+ 		ResolvableType  resolvedType ;
176+ 		if  (contextType .hasGenerics ()) {
177+ 			resolvedType  = ResolvableType .forType (typeVariable , contextType );
178+ 			if  (resolvedType .resolve () != null ) {
179+ 				return  resolvedType ;
180+ 			}
314181		}
315182
316- 		@ Override 
317- 		public  ResolvableType  resolveVariable (TypeVariable <?> variable ) {
318- 			Type  type  = this .typeVariableMap .get (variable );
319- 			return  (type  != null  ? ResolvableType .forType (type ) : null );
183+ 		ResolvableType  superType  = contextType .getSuperType ();
184+ 		if  (superType  != ResolvableType .NONE ) {
185+ 			resolvedType  = resolveVariable (typeVariable , superType );
186+ 			if  (resolvedType .resolve () != null ) {
187+ 				return  resolvedType ;
188+ 			}
320189		}
321- 
322- 		@ Override 
323- 		public  Object  getSource () {
324- 			return  this .typeVariableMap ;
190+ 		for  (ResolvableType  ifc  : contextType .getInterfaces ()) {
191+ 			resolvedType  = resolveVariable (typeVariable , ifc );
192+ 			if  (resolvedType .resolve () != null ) {
193+ 				return  resolvedType ;
194+ 			}
325195		}
196+ 		return  ResolvableType .NONE ;
326197	}
327198
328199}
0 commit comments