18
18
19
19
import java .beans .PropertyDescriptor ;
20
20
import java .io .Serializable ;
21
+ import java .lang .annotation .Annotation ;
22
+ import java .lang .reflect .AnnotatedElement ;
21
23
import java .lang .reflect .Constructor ;
22
24
import java .lang .reflect .Executable ;
23
25
import java .lang .reflect .InvocationHandler ;
24
26
import java .lang .reflect .InvocationTargetException ;
25
27
import java .lang .reflect .Method ;
26
28
import java .lang .reflect .Modifier ;
29
+ import java .lang .reflect .Parameter ;
27
30
import java .lang .reflect .ParameterizedType ;
28
31
import java .lang .reflect .Proxy ;
29
32
import java .lang .reflect .Type ;
33
36
import java .util .Set ;
34
37
35
38
import org .springframework .beans .BeanMetadataElement ;
39
+ import org .springframework .beans .BeansException ;
36
40
import org .springframework .beans .factory .ObjectFactory ;
41
+ import org .springframework .beans .factory .annotation .Autowired ;
42
+ import org .springframework .beans .factory .annotation .Qualifier ;
43
+ import org .springframework .beans .factory .annotation .Value ;
44
+ import org .springframework .beans .factory .config .AutowireCapableBeanFactory ;
45
+ import org .springframework .beans .factory .config .DependencyDescriptor ;
37
46
import org .springframework .beans .factory .config .TypedStringValue ;
47
+ import org .springframework .core .MethodParameter ;
48
+ import org .springframework .core .annotation .AnnotatedElementUtils ;
49
+ import org .springframework .core .annotation .SynthesizingMethodParameter ;
38
50
import org .springframework .lang .Nullable ;
39
51
import org .springframework .util .Assert ;
40
52
import org .springframework .util .ClassUtils ;
49
61
* @since 1.1.2
50
62
* @see AbstractAutowireCapableBeanFactory
51
63
*/
52
- abstract class AutowireUtils {
64
+ public abstract class AutowireUtils {
53
65
54
66
private static final Comparator <Executable > EXECUTABLE_COMPARATOR = (e1 , e2 ) -> {
55
67
int result = Boolean .compare (Modifier .isPublic (e2 .getModifiers ()), Modifier .isPublic (e1 .getModifiers ()));
56
68
return result != 0 ? result : Integer .compare (e2 .getParameterCount (), e1 .getParameterCount ());
57
69
};
58
70
71
+ private static final AnnotatedElement EMPTY_ANNOTATED_ELEMENT = new AnnotatedElement () {
72
+ @ Override
73
+ @ Nullable
74
+ public <T extends Annotation > T getAnnotation (Class <T > annotationClass ) {
75
+ return null ;
76
+ }
77
+ @ Override
78
+ public Annotation [] getAnnotations () {
79
+ return new Annotation [0 ];
80
+ }
81
+ @ Override
82
+ public Annotation [] getDeclaredAnnotations () {
83
+ return new Annotation [0 ];
84
+ }
85
+ };
86
+
59
87
60
88
/**
61
89
* Sort the given constructors, preferring public constructors and "greedy" ones with
@@ -64,7 +92,7 @@ abstract class AutowireUtils {
64
92
* decreasing number of arguments.
65
93
* @param constructors the constructor array to sort
66
94
*/
67
- public static void sortConstructors (Constructor <?>[] constructors ) {
95
+ static void sortConstructors (Constructor <?>[] constructors ) {
68
96
Arrays .sort (constructors , EXECUTABLE_COMPARATOR );
69
97
}
70
98
@@ -75,7 +103,7 @@ public static void sortConstructors(Constructor<?>[] constructors) {
75
103
* decreasing number of arguments.
76
104
* @param factoryMethods the factory method array to sort
77
105
*/
78
- public static void sortFactoryMethods (Method [] factoryMethods ) {
106
+ static void sortFactoryMethods (Method [] factoryMethods ) {
79
107
Arrays .sort (factoryMethods , EXECUTABLE_COMPARATOR );
80
108
}
81
109
@@ -85,7 +113,7 @@ public static void sortFactoryMethods(Method[] factoryMethods) {
85
113
* @param pd the PropertyDescriptor of the bean property
86
114
* @return whether the bean property is excluded
87
115
*/
88
- public static boolean isExcludedFromDependencyCheck (PropertyDescriptor pd ) {
116
+ static boolean isExcludedFromDependencyCheck (PropertyDescriptor pd ) {
89
117
Method wm = pd .getWriteMethod ();
90
118
if (wm == null ) {
91
119
return false ;
@@ -107,7 +135,7 @@ public static boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {
107
135
* @param interfaces the Set of interfaces (Class objects)
108
136
* @return whether the setter method is defined by an interface
109
137
*/
110
- public static boolean isSetterDefinedInInterface (PropertyDescriptor pd , Set <Class <?>> interfaces ) {
138
+ static boolean isSetterDefinedInInterface (PropertyDescriptor pd , Set <Class <?>> interfaces ) {
111
139
Method setter = pd .getWriteMethod ();
112
140
if (setter != null ) {
113
141
Class <?> targetClass = setter .getDeclaringClass ();
@@ -128,7 +156,7 @@ public static boolean isSetterDefinedInInterface(PropertyDescriptor pd, Set<Clas
128
156
* @param requiredType the type to assign the result to
129
157
* @return the resolved value
130
158
*/
131
- public static Object resolveAutowiringValue (Object autowiringValue , Class <?> requiredType ) {
159
+ static Object resolveAutowiringValue (Object autowiringValue , Class <?> requiredType ) {
132
160
if (autowiringValue instanceof ObjectFactory && !requiredType .isInstance (autowiringValue )) {
133
161
ObjectFactory <?> factory = (ObjectFactory <?>) autowiringValue ;
134
162
if (autowiringValue instanceof Serializable && requiredType .isInterface ()) {
@@ -173,7 +201,7 @@ public static Object resolveAutowiringValue(Object autowiringValue, Class<?> req
173
201
* @return the resolved target return type or the standard method return type
174
202
* @since 3.2.5
175
203
*/
176
- public static Class <?> resolveReturnTypeForFactoryMethod (
204
+ static Class <?> resolveReturnTypeForFactoryMethod (
177
205
Method method , Object [] args , @ Nullable ClassLoader classLoader ) {
178
206
179
207
Assert .notNull (method , "Method must not be null" );
@@ -264,6 +292,103 @@ else if (arg instanceof TypedStringValue) {
264
292
return method .getReturnType ();
265
293
}
266
294
295
+ /**
296
+ * Determine if the supplied {@link Parameter} can <em>potentially</em> be
297
+ * autowired from an {@link AutowireCapableBeanFactory}.
298
+ * <p>Returns {@code true} if the supplied parameter is annotated or
299
+ * meta-annotated with {@link Autowired @Autowired},
300
+ * {@link Qualifier @Qualifier}, or {@link Value @Value}.
301
+ * <p>Note that {@link #resolveDependency} may still be able to resolve the
302
+ * dependency for the supplied parameter even if this method returns {@code false}.
303
+ * @param parameter the parameter whose dependency should be autowired
304
+ * @param parameterIndex the index of the parameter in the constructor or method
305
+ * that declares the parameter
306
+ * @see #resolveDependency
307
+ * @since 5.2
308
+ */
309
+ public static boolean isAutowirable (Parameter parameter , int parameterIndex ) {
310
+ AnnotatedElement annotatedParameter = getEffectiveAnnotatedParameter (parameter , parameterIndex );
311
+ return (AnnotatedElementUtils .hasAnnotation (annotatedParameter , Autowired .class ) ||
312
+ AnnotatedElementUtils .hasAnnotation (annotatedParameter , Qualifier .class ) ||
313
+ AnnotatedElementUtils .hasAnnotation (annotatedParameter , Value .class ));
314
+ }
315
+
316
+ /**
317
+ * Resolve the dependency for the supplied {@link Parameter} from the
318
+ * supplied {@link AutowireCapableBeanFactory}.
319
+ * <p>Provides comprehensive autowiring support for individual method parameters
320
+ * on par with Spring's dependency injection facilities for autowired fields and
321
+ * methods, including support for {@link Autowired @Autowired},
322
+ * {@link Qualifier @Qualifier}, and {@link Value @Value} with support for property
323
+ * placeholders and SpEL expressions in {@code @Value} declarations.
324
+ * <p>The dependency is required unless the parameter is annotated or meta-annotated
325
+ * with {@link Autowired @Autowired} with the {@link Autowired#required required}
326
+ * flag set to {@code false}.
327
+ * <p>If an explicit <em>qualifier</em> is not declared, the name of the parameter
328
+ * will be used as the qualifier for resolving ambiguities.
329
+ * @param parameter the parameter whose dependency should be resolved
330
+ * @param parameterIndex the index of the parameter in the constructor or method
331
+ * that declares the parameter
332
+ * @param containingClass the concrete class that contains the parameter; this may
333
+ * differ from the class that declares the parameter in that it may be a subclass
334
+ * thereof, potentially substituting type variables
335
+ * @param beanFactory the {@code AutowireCapableBeanFactory} from which to resolve
336
+ * the dependency
337
+ * @return the resolved object, or {@code null} if none found
338
+ * @throws BeansException if dependency resolution failed
339
+ * @see #isAutowirable
340
+ * @see Autowired#required
341
+ * @see SynthesizingMethodParameter#forExecutable(Executable, int)
342
+ * @see AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String)
343
+ * @since 5.2
344
+ */
345
+ @ Nullable
346
+ public static Object resolveDependency (
347
+ Parameter parameter , int parameterIndex , Class <?> containingClass , AutowireCapableBeanFactory beanFactory )
348
+ throws BeansException {
349
+
350
+ AnnotatedElement annotatedParameter = getEffectiveAnnotatedParameter (parameter , parameterIndex );
351
+ Autowired autowired = AnnotatedElementUtils .findMergedAnnotation (annotatedParameter , Autowired .class );
352
+ boolean required = (autowired == null || autowired .required ());
353
+
354
+ MethodParameter methodParameter = SynthesizingMethodParameter .forExecutable (
355
+ parameter .getDeclaringExecutable (), parameterIndex );
356
+ DependencyDescriptor descriptor = new DependencyDescriptor (methodParameter , required );
357
+ descriptor .setContainingClass (containingClass );
358
+ return beanFactory .resolveDependency (descriptor , null );
359
+ }
360
+
361
+ /**
362
+ * Due to a bug in {@code javac} on JDK versions prior to JDK 9, looking up
363
+ * annotations directly on a {@link Parameter} will fail for inner class
364
+ * constructors.
365
+ * <h4>Bug in javac in JDK < 9</h4>
366
+ * <p>The parameter annotations array in the compiled byte code excludes an entry
367
+ * for the implicit <em>enclosing instance</em> parameter for an inner class
368
+ * constructor.
369
+ * <h4>Workaround</h4>
370
+ * <p>This method provides a workaround for this off-by-one error by allowing the
371
+ * caller to access annotations on the preceding {@link Parameter} object (i.e.,
372
+ * {@code index - 1}). If the supplied {@code index} is zero, this method returns
373
+ * an empty {@code AnnotatedElement}.
374
+ * <h4>WARNING</h4>
375
+ * <p>The {@code AnnotatedElement} returned by this method should never be cast and
376
+ * treated as a {@code Parameter} since the metadata (e.g., {@link Parameter#getName()},
377
+ * {@link Parameter#getType()}, etc.) will not match those for the declared parameter
378
+ * at the given index in an inner class constructor.
379
+ * @return the supplied {@code parameter} or the <em>effective</em> {@code Parameter}
380
+ * if the aforementioned bug is in effect
381
+ */
382
+ private static AnnotatedElement getEffectiveAnnotatedParameter (Parameter parameter , int index ) {
383
+ Executable executable = parameter .getDeclaringExecutable ();
384
+ if (executable instanceof Constructor && ClassUtils .isInnerClass (executable .getDeclaringClass ()) &&
385
+ executable .getParameterAnnotations ().length == executable .getParameterCount () - 1 ) {
386
+ // Bug in javac in JDK <9: annotation array excludes enclosing instance parameter
387
+ // for inner classes, so access it with the actual parameter index lowered by 1
388
+ return (index == 0 ? EMPTY_ANNOTATED_ELEMENT : executable .getParameters ()[index - 1 ]);
389
+ }
390
+ return parameter ;
391
+ }
267
392
268
393
/**
269
394
* Reflective InvocationHandler for lazy access to the current target object.
0 commit comments