001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.factory.annotation;
018
019import java.beans.PropertyDescriptor;
020import java.lang.annotation.Annotation;
021import java.lang.reflect.AccessibleObject;
022import java.lang.reflect.Constructor;
023import java.lang.reflect.Field;
024import java.lang.reflect.InvocationTargetException;
025import java.lang.reflect.Method;
026import java.lang.reflect.Modifier;
027import java.util.ArrayList;
028import java.util.Arrays;
029import java.util.Collections;
030import java.util.Iterator;
031import java.util.LinkedHashSet;
032import java.util.List;
033import java.util.Map;
034import java.util.Set;
035import java.util.concurrent.ConcurrentHashMap;
036
037import org.apache.commons.logging.Log;
038import org.apache.commons.logging.LogFactory;
039
040import org.springframework.beans.BeanUtils;
041import org.springframework.beans.BeansException;
042import org.springframework.beans.PropertyValues;
043import org.springframework.beans.TypeConverter;
044import org.springframework.beans.factory.BeanCreationException;
045import org.springframework.beans.factory.BeanFactory;
046import org.springframework.beans.factory.BeanFactoryAware;
047import org.springframework.beans.factory.BeanFactoryUtils;
048import org.springframework.beans.factory.InjectionPoint;
049import org.springframework.beans.factory.NoSuchBeanDefinitionException;
050import org.springframework.beans.factory.UnsatisfiedDependencyException;
051import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
052import org.springframework.beans.factory.config.DependencyDescriptor;
053import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
054import org.springframework.beans.factory.support.LookupOverride;
055import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
056import org.springframework.beans.factory.support.RootBeanDefinition;
057import org.springframework.core.BridgeMethodResolver;
058import org.springframework.core.MethodParameter;
059import org.springframework.core.Ordered;
060import org.springframework.core.PriorityOrdered;
061import org.springframework.core.annotation.AnnotationAttributes;
062import org.springframework.core.annotation.AnnotationUtils;
063import org.springframework.core.annotation.MergedAnnotation;
064import org.springframework.core.annotation.MergedAnnotations;
065import org.springframework.lang.Nullable;
066import org.springframework.util.Assert;
067import org.springframework.util.ClassUtils;
068import org.springframework.util.ReflectionUtils;
069import org.springframework.util.StringUtils;
070
071/**
072 * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}
073 * implementation that autowires annotated fields, setter methods, and arbitrary
074 * config methods. Such members to be injected are detected through annotations:
075 * by default, Spring's {@link Autowired @Autowired} and {@link Value @Value}
076 * annotations.
077 *
078 * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
079 * if available, as a direct alternative to Spring's own {@code @Autowired}.
080 *
081 * <h3>Autowired Constructors</h3>
082 * <p>Only one constructor of any given bean class may declare this annotation with
083 * the 'required' attribute set to {@code true}, indicating <i>the</i> constructor
084 * to autowire when used as a Spring bean. Furthermore, if the 'required' attribute
085 * is set to {@code true}, only a single constructor may be annotated with
086 * {@code @Autowired}. If multiple <i>non-required</i> constructors declare the
087 * annotation, they will be considered as candidates for autowiring. The constructor
088 * with the greatest number of dependencies that can be satisfied by matching beans
089 * in the Spring container will be chosen. If none of the candidates can be satisfied,
090 * then a primary/default constructor (if present) will be used. If a class only
091 * declares a single constructor to begin with, it will always be used, even if not
092 * annotated. An annotated constructor does not have to be public.
093 *
094 * <h3>Autowired Fields</h3>
095 * <p>Fields are injected right after construction of a bean, before any
096 * config methods are invoked. Such a config field does not have to be public.
097 *
098 * <h3>Autowired Methods</h3>
099 * <p>Config methods may have an arbitrary name and any number of arguments; each of
100 * those arguments will be autowired with a matching bean in the Spring container.
101 * Bean property setter methods are effectively just a special case of such a
102 * general config method. Config methods do not have to be public.
103 *
104 * <h3>Annotation Config vs. XML Config</h3>
105 * <p>A default {@code AutowiredAnnotationBeanPostProcessor} will be registered
106 * by the "context:annotation-config" and "context:component-scan" XML tags.
107 * Remove or turn off the default annotation configuration there if you intend
108 * to specify a custom {@code AutowiredAnnotationBeanPostProcessor} bean definition.
109 *
110 * <p><b>NOTE:</b> Annotation injection will be performed <i>before</i> XML injection;
111 * thus the latter configuration will override the former for properties wired through
112 * both approaches.
113 *
114 * <h3>{@literal @}Lookup Methods</h3>
115 * <p>In addition to regular injection points as discussed above, this post-processor
116 * also handles Spring's {@link Lookup @Lookup} annotation which identifies lookup
117 * methods to be replaced by the container at runtime. This is essentially a type-safe
118 * version of {@code getBean(Class, args)} and {@code getBean(String, args)}.
119 * See {@link Lookup @Lookup's javadoc} for details.
120 *
121 * @author Juergen Hoeller
122 * @author Mark Fisher
123 * @author Stephane Nicoll
124 * @author Sebastien Deleuze
125 * @author Sam Brannen
126 * @since 2.5
127 * @see #setAutowiredAnnotationType
128 * @see Autowired
129 * @see Value
130 */
131public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
132                implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
133
134        protected final Log logger = LogFactory.getLog(getClass());
135
136        private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
137
138        private String requiredParameterName = "required";
139
140        private boolean requiredParameterValue = true;
141
142        private int order = Ordered.LOWEST_PRECEDENCE - 2;
143
144        @Nullable
145        private ConfigurableListableBeanFactory beanFactory;
146
147        private final Set<String> lookupMethodsChecked = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
148
149        private final Map<Class<?>, Constructor<?>[]> candidateConstructorsCache = new ConcurrentHashMap<>(256);
150
151        private final Map<String, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<>(256);
152
153
154        /**
155         * Create a new {@code AutowiredAnnotationBeanPostProcessor} for Spring's
156         * standard {@link Autowired @Autowired} and {@link Value @Value} annotations.
157         * <p>Also supports JSR-330's {@link javax.inject.Inject @Inject} annotation,
158         * if available.
159         */
160        @SuppressWarnings("unchecked")
161        public AutowiredAnnotationBeanPostProcessor() {
162                this.autowiredAnnotationTypes.add(Autowired.class);
163                this.autowiredAnnotationTypes.add(Value.class);
164                try {
165                        this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
166                                        ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
167                        logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
168                }
169                catch (ClassNotFoundException ex) {
170                        // JSR-330 API not available - simply skip.
171                }
172        }
173
174
175        /**
176         * Set the 'autowired' annotation type, to be used on constructors, fields,
177         * setter methods, and arbitrary config methods.
178         * <p>The default autowired annotation types are the Spring-provided
179         * {@link Autowired @Autowired} and {@link Value @Value} annotations as well
180         * as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available.
181         * <p>This setter property exists so that developers can provide their own
182         * (non-Spring-specific) annotation type to indicate that a member is supposed
183         * to be autowired.
184         */
185        public void setAutowiredAnnotationType(Class<? extends Annotation> autowiredAnnotationType) {
186                Assert.notNull(autowiredAnnotationType, "'autowiredAnnotationType' must not be null");
187                this.autowiredAnnotationTypes.clear();
188                this.autowiredAnnotationTypes.add(autowiredAnnotationType);
189        }
190
191        /**
192         * Set the 'autowired' annotation types, to be used on constructors, fields,
193         * setter methods, and arbitrary config methods.
194         * <p>The default autowired annotation types are the Spring-provided
195         * {@link Autowired @Autowired} and {@link Value @Value} annotations as well
196         * as JSR-330's {@link javax.inject.Inject @Inject} annotation, if available.
197         * <p>This setter property exists so that developers can provide their own
198         * (non-Spring-specific) annotation types to indicate that a member is supposed
199         * to be autowired.
200         */
201        public void setAutowiredAnnotationTypes(Set<Class<? extends Annotation>> autowiredAnnotationTypes) {
202                Assert.notEmpty(autowiredAnnotationTypes, "'autowiredAnnotationTypes' must not be empty");
203                this.autowiredAnnotationTypes.clear();
204                this.autowiredAnnotationTypes.addAll(autowiredAnnotationTypes);
205        }
206
207        /**
208         * Set the name of an attribute of the annotation that specifies whether it is required.
209         * @see #setRequiredParameterValue(boolean)
210         */
211        public void setRequiredParameterName(String requiredParameterName) {
212                this.requiredParameterName = requiredParameterName;
213        }
214
215        /**
216         * Set the boolean value that marks a dependency as required.
217         * <p>For example if using 'required=true' (the default), this value should be
218         * {@code true}; but if using 'optional=false', this value should be {@code false}.
219         * @see #setRequiredParameterName(String)
220         */
221        public void setRequiredParameterValue(boolean requiredParameterValue) {
222                this.requiredParameterValue = requiredParameterValue;
223        }
224
225        public void setOrder(int order) {
226                this.order = order;
227        }
228
229        @Override
230        public int getOrder() {
231                return this.order;
232        }
233
234        @Override
235        public void setBeanFactory(BeanFactory beanFactory) {
236                if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
237                        throw new IllegalArgumentException(
238                                        "AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory: " + beanFactory);
239                }
240                this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
241        }
242
243
244        @Override
245        public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
246                InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
247                metadata.checkConfigMembers(beanDefinition);
248        }
249
250        @Override
251        public void resetBeanDefinition(String beanName) {
252                this.lookupMethodsChecked.remove(beanName);
253                this.injectionMetadataCache.remove(beanName);
254        }
255
256        @Override
257        @Nullable
258        public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
259                        throws BeanCreationException {
260
261                // Let's check for lookup methods here...
262                if (!this.lookupMethodsChecked.contains(beanName)) {
263                        if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
264                                try {
265                                        Class<?> targetClass = beanClass;
266                                        do {
267                                                ReflectionUtils.doWithLocalMethods(targetClass, method -> {
268                                                        Lookup lookup = method.getAnnotation(Lookup.class);
269                                                        if (lookup != null) {
270                                                                Assert.state(this.beanFactory != null, "No BeanFactory available");
271                                                                LookupOverride override = new LookupOverride(method, lookup.value());
272                                                                try {
273                                                                        RootBeanDefinition mbd = (RootBeanDefinition)
274                                                                                        this.beanFactory.getMergedBeanDefinition(beanName);
275                                                                        mbd.getMethodOverrides().addOverride(override);
276                                                                }
277                                                                catch (NoSuchBeanDefinitionException ex) {
278                                                                        throw new BeanCreationException(beanName,
279                                                                                        "Cannot apply @Lookup to beans without corresponding bean definition");
280                                                                }
281                                                        }
282                                                });
283                                                targetClass = targetClass.getSuperclass();
284                                        }
285                                        while (targetClass != null && targetClass != Object.class);
286
287                                }
288                                catch (IllegalStateException ex) {
289                                        throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
290                                }
291                        }
292                        this.lookupMethodsChecked.add(beanName);
293                }
294
295                // Quick check on the concurrent map first, with minimal locking.
296                Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
297                if (candidateConstructors == null) {
298                        // Fully synchronized resolution now...
299                        synchronized (this.candidateConstructorsCache) {
300                                candidateConstructors = this.candidateConstructorsCache.get(beanClass);
301                                if (candidateConstructors == null) {
302                                        Constructor<?>[] rawCandidates;
303                                        try {
304                                                rawCandidates = beanClass.getDeclaredConstructors();
305                                        }
306                                        catch (Throwable ex) {
307                                                throw new BeanCreationException(beanName,
308                                                                "Resolution of declared constructors on bean Class [" + beanClass.getName() +
309                                                                "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
310                                        }
311                                        List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
312                                        Constructor<?> requiredConstructor = null;
313                                        Constructor<?> defaultConstructor = null;
314                                        Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
315                                        int nonSyntheticConstructors = 0;
316                                        for (Constructor<?> candidate : rawCandidates) {
317                                                if (!candidate.isSynthetic()) {
318                                                        nonSyntheticConstructors++;
319                                                }
320                                                else if (primaryConstructor != null) {
321                                                        continue;
322                                                }
323                                                MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
324                                                if (ann == null) {
325                                                        Class<?> userClass = ClassUtils.getUserClass(beanClass);
326                                                        if (userClass != beanClass) {
327                                                                try {
328                                                                        Constructor<?> superCtor =
329                                                                                        userClass.getDeclaredConstructor(candidate.getParameterTypes());
330                                                                        ann = findAutowiredAnnotation(superCtor);
331                                                                }
332                                                                catch (NoSuchMethodException ex) {
333                                                                        // Simply proceed, no equivalent superclass constructor found...
334                                                                }
335                                                        }
336                                                }
337                                                if (ann != null) {
338                                                        if (requiredConstructor != null) {
339                                                                throw new BeanCreationException(beanName,
340                                                                                "Invalid autowire-marked constructor: " + candidate +
341                                                                                ". Found constructor with 'required' Autowired annotation already: " +
342                                                                                requiredConstructor);
343                                                        }
344                                                        boolean required = determineRequiredStatus(ann);
345                                                        if (required) {
346                                                                if (!candidates.isEmpty()) {
347                                                                        throw new BeanCreationException(beanName,
348                                                                                        "Invalid autowire-marked constructors: " + candidates +
349                                                                                        ". Found constructor with 'required' Autowired annotation: " +
350                                                                                        candidate);
351                                                                }
352                                                                requiredConstructor = candidate;
353                                                        }
354                                                        candidates.add(candidate);
355                                                }
356                                                else if (candidate.getParameterCount() == 0) {
357                                                        defaultConstructor = candidate;
358                                                }
359                                        }
360                                        if (!candidates.isEmpty()) {
361                                                // Add default constructor to list of optional constructors, as fallback.
362                                                if (requiredConstructor == null) {
363                                                        if (defaultConstructor != null) {
364                                                                candidates.add(defaultConstructor);
365                                                        }
366                                                        else if (candidates.size() == 1 && logger.isInfoEnabled()) {
367                                                                logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
368                                                                                "': single autowire-marked constructor flagged as optional - " +
369                                                                                "this constructor is effectively required since there is no " +
370                                                                                "default constructor to fall back to: " + candidates.get(0));
371                                                        }
372                                                }
373                                                candidateConstructors = candidates.toArray(new Constructor<?>[0]);
374                                        }
375                                        else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
376                                                candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
377                                        }
378                                        else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
379                                                        defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
380                                                candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
381                                        }
382                                        else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
383                                                candidateConstructors = new Constructor<?>[] {primaryConstructor};
384                                        }
385                                        else {
386                                                candidateConstructors = new Constructor<?>[0];
387                                        }
388                                        this.candidateConstructorsCache.put(beanClass, candidateConstructors);
389                                }
390                        }
391                }
392                return (candidateConstructors.length > 0 ? candidateConstructors : null);
393        }
394
395        @Override
396        public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
397                InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
398                try {
399                        metadata.inject(bean, beanName, pvs);
400                }
401                catch (BeanCreationException ex) {
402                        throw ex;
403                }
404                catch (Throwable ex) {
405                        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
406                }
407                return pvs;
408        }
409
410        @Deprecated
411        @Override
412        public PropertyValues postProcessPropertyValues(
413                        PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
414
415                return postProcessProperties(pvs, bean, beanName);
416        }
417
418        /**
419         * 'Native' processing method for direct calls with an arbitrary target instance,
420         * resolving all of its fields and methods which are annotated with one of the
421         * configured 'autowired' annotation types.
422         * @param bean the target instance to process
423         * @throws BeanCreationException if autowiring failed
424         * @see #setAutowiredAnnotationTypes(Set)
425         */
426        public void processInjection(Object bean) throws BeanCreationException {
427                Class<?> clazz = bean.getClass();
428                InjectionMetadata metadata = findAutowiringMetadata(clazz.getName(), clazz, null);
429                try {
430                        metadata.inject(bean, null, null);
431                }
432                catch (BeanCreationException ex) {
433                        throw ex;
434                }
435                catch (Throwable ex) {
436                        throw new BeanCreationException(
437                                        "Injection of autowired dependencies failed for class [" + clazz + "]", ex);
438                }
439        }
440
441
442        private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
443                // Fall back to class name as cache key, for backwards compatibility with custom callers.
444                String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
445                // Quick check on the concurrent map first, with minimal locking.
446                InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
447                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
448                        synchronized (this.injectionMetadataCache) {
449                                metadata = this.injectionMetadataCache.get(cacheKey);
450                                if (InjectionMetadata.needsRefresh(metadata, clazz)) {
451                                        if (metadata != null) {
452                                                metadata.clear(pvs);
453                                        }
454                                        metadata = buildAutowiringMetadata(clazz);
455                                        this.injectionMetadataCache.put(cacheKey, metadata);
456                                }
457                        }
458                }
459                return metadata;
460        }
461
462        private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
463                if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
464                        return InjectionMetadata.EMPTY;
465                }
466
467                List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
468                Class<?> targetClass = clazz;
469
470                do {
471                        final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
472
473                        ReflectionUtils.doWithLocalFields(targetClass, field -> {
474                                MergedAnnotation<?> ann = findAutowiredAnnotation(field);
475                                if (ann != null) {
476                                        if (Modifier.isStatic(field.getModifiers())) {
477                                                if (logger.isInfoEnabled()) {
478                                                        logger.info("Autowired annotation is not supported on static fields: " + field);
479                                                }
480                                                return;
481                                        }
482                                        boolean required = determineRequiredStatus(ann);
483                                        currElements.add(new AutowiredFieldElement(field, required));
484                                }
485                        });
486
487                        ReflectionUtils.doWithLocalMethods(targetClass, method -> {
488                                Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
489                                if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
490                                        return;
491                                }
492                                MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
493                                if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
494                                        if (Modifier.isStatic(method.getModifiers())) {
495                                                if (logger.isInfoEnabled()) {
496                                                        logger.info("Autowired annotation is not supported on static methods: " + method);
497                                                }
498                                                return;
499                                        }
500                                        if (method.getParameterCount() == 0) {
501                                                if (logger.isInfoEnabled()) {
502                                                        logger.info("Autowired annotation should only be used on methods with parameters: " +
503                                                                        method);
504                                                }
505                                        }
506                                        boolean required = determineRequiredStatus(ann);
507                                        PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
508                                        currElements.add(new AutowiredMethodElement(method, required, pd));
509                                }
510                        });
511
512                        elements.addAll(0, currElements);
513                        targetClass = targetClass.getSuperclass();
514                }
515                while (targetClass != null && targetClass != Object.class);
516
517                return InjectionMetadata.forElements(elements, clazz);
518        }
519
520        @Nullable
521        private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
522                MergedAnnotations annotations = MergedAnnotations.from(ao);
523                for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
524                        MergedAnnotation<?> annotation = annotations.get(type);
525                        if (annotation.isPresent()) {
526                                return annotation;
527                        }
528                }
529                return null;
530        }
531
532        /**
533         * Determine if the annotated field or method requires its dependency.
534         * <p>A 'required' dependency means that autowiring should fail when no beans
535         * are found. Otherwise, the autowiring process will simply bypass the field
536         * or method when no beans are found.
537         * @param ann the Autowired annotation
538         * @return whether the annotation indicates that a dependency is required
539         */
540        @SuppressWarnings({"deprecation", "cast"})
541        protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {
542                // The following (AnnotationAttributes) cast is required on JDK 9+.
543                return determineRequiredStatus((AnnotationAttributes)
544                                ann.asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType())));
545        }
546
547        /**
548         * Determine if the annotated field or method requires its dependency.
549         * <p>A 'required' dependency means that autowiring should fail when no beans
550         * are found. Otherwise, the autowiring process will simply bypass the field
551         * or method when no beans are found.
552         * @param ann the Autowired annotation
553         * @return whether the annotation indicates that a dependency is required
554         * @deprecated since 5.2, in favor of {@link #determineRequiredStatus(MergedAnnotation)}
555         */
556        @Deprecated
557        protected boolean determineRequiredStatus(AnnotationAttributes ann) {
558                return (!ann.containsKey(this.requiredParameterName) ||
559                                this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
560        }
561
562        /**
563         * Obtain all beans of the given type as autowire candidates.
564         * @param type the type of the bean
565         * @return the target beans, or an empty Collection if no bean of this type is found
566         * @throws BeansException if bean retrieval failed
567         */
568        protected <T> Map<String, T> findAutowireCandidates(Class<T> type) throws BeansException {
569                if (this.beanFactory == null) {
570                        throw new IllegalStateException("No BeanFactory configured - " +
571                                        "override the getBeanOfType method or specify the 'beanFactory' property");
572                }
573                return BeanFactoryUtils.beansOfTypeIncludingAncestors(this.beanFactory, type);
574        }
575
576        /**
577         * Register the specified bean as dependent on the autowired beans.
578         */
579        private void registerDependentBeans(@Nullable String beanName, Set<String> autowiredBeanNames) {
580                if (beanName != null) {
581                        for (String autowiredBeanName : autowiredBeanNames) {
582                                if (this.beanFactory != null && this.beanFactory.containsBean(autowiredBeanName)) {
583                                        this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
584                                }
585                                if (logger.isTraceEnabled()) {
586                                        logger.trace("Autowiring by type from bean name '" + beanName +
587                                                        "' to bean named '" + autowiredBeanName + "'");
588                                }
589                        }
590                }
591        }
592
593        /**
594         * Resolve the specified cached method argument or field value.
595         */
596        @Nullable
597        private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
598                if (cachedArgument instanceof DependencyDescriptor) {
599                        DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
600                        Assert.state(this.beanFactory != null, "No BeanFactory available");
601                        return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
602                }
603                else {
604                        return cachedArgument;
605                }
606        }
607
608
609        /**
610         * Class representing injection information about an annotated field.
611         */
612        private class AutowiredFieldElement extends InjectionMetadata.InjectedElement {
613
614                private final boolean required;
615
616                private volatile boolean cached;
617
618                @Nullable
619                private volatile Object cachedFieldValue;
620
621                public AutowiredFieldElement(Field field, boolean required) {
622                        super(field, null);
623                        this.required = required;
624                }
625
626                @Override
627                protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
628                        Field field = (Field) this.member;
629                        Object value;
630                        if (this.cached) {
631                                value = resolvedCachedArgument(beanName, this.cachedFieldValue);
632                        }
633                        else {
634                                DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
635                                desc.setContainingClass(bean.getClass());
636                                Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
637                                Assert.state(beanFactory != null, "No BeanFactory available");
638                                TypeConverter typeConverter = beanFactory.getTypeConverter();
639                                try {
640                                        value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
641                                }
642                                catch (BeansException ex) {
643                                        throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
644                                }
645                                synchronized (this) {
646                                        if (!this.cached) {
647                                                Object cachedFieldValue = null;
648                                                if (value != null || this.required) {
649                                                        cachedFieldValue = desc;
650                                                        registerDependentBeans(beanName, autowiredBeanNames);
651                                                        if (autowiredBeanNames.size() == 1) {
652                                                                String autowiredBeanName = autowiredBeanNames.iterator().next();
653                                                                if (beanFactory.containsBean(autowiredBeanName) &&
654                                                                                beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
655                                                                        cachedFieldValue = new ShortcutDependencyDescriptor(
656                                                                                        desc, autowiredBeanName, field.getType());
657                                                                }
658                                                        }
659                                                }
660                                                this.cachedFieldValue = cachedFieldValue;
661                                                this.cached = true;
662                                        }
663                                }
664                        }
665                        if (value != null) {
666                                ReflectionUtils.makeAccessible(field);
667                                field.set(bean, value);
668                        }
669                }
670        }
671
672
673        /**
674         * Class representing injection information about an annotated method.
675         */
676        private class AutowiredMethodElement extends InjectionMetadata.InjectedElement {
677
678                private final boolean required;
679
680                private volatile boolean cached;
681
682                @Nullable
683                private volatile Object[] cachedMethodArguments;
684
685                public AutowiredMethodElement(Method method, boolean required, @Nullable PropertyDescriptor pd) {
686                        super(method, pd);
687                        this.required = required;
688                }
689
690                @Override
691                protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
692                        if (checkPropertySkipping(pvs)) {
693                                return;
694                        }
695                        Method method = (Method) this.member;
696                        Object[] arguments;
697                        if (this.cached) {
698                                // Shortcut for avoiding synchronization...
699                                arguments = resolveCachedArguments(beanName);
700                        }
701                        else {
702                                int argumentCount = method.getParameterCount();
703                                arguments = new Object[argumentCount];
704                                DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
705                                Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
706                                Assert.state(beanFactory != null, "No BeanFactory available");
707                                TypeConverter typeConverter = beanFactory.getTypeConverter();
708                                for (int i = 0; i < arguments.length; i++) {
709                                        MethodParameter methodParam = new MethodParameter(method, i);
710                                        DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
711                                        currDesc.setContainingClass(bean.getClass());
712                                        descriptors[i] = currDesc;
713                                        try {
714                                                Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
715                                                if (arg == null && !this.required) {
716                                                        arguments = null;
717                                                        break;
718                                                }
719                                                arguments[i] = arg;
720                                        }
721                                        catch (BeansException ex) {
722                                                throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
723                                        }
724                                }
725                                synchronized (this) {
726                                        if (!this.cached) {
727                                                if (arguments != null) {
728                                                        DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
729                                                        registerDependentBeans(beanName, autowiredBeans);
730                                                        if (autowiredBeans.size() == argumentCount) {
731                                                                Iterator<String> it = autowiredBeans.iterator();
732                                                                Class<?>[] paramTypes = method.getParameterTypes();
733                                                                for (int i = 0; i < paramTypes.length; i++) {
734                                                                        String autowiredBeanName = it.next();
735                                                                        if (beanFactory.containsBean(autowiredBeanName) &&
736                                                                                        beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
737                                                                                cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
738                                                                                                descriptors[i], autowiredBeanName, paramTypes[i]);
739                                                                        }
740                                                                }
741                                                        }
742                                                        this.cachedMethodArguments = cachedMethodArguments;
743                                                }
744                                                else {
745                                                        this.cachedMethodArguments = null;
746                                                }
747                                                this.cached = true;
748                                        }
749                                }
750                        }
751                        if (arguments != null) {
752                                try {
753                                        ReflectionUtils.makeAccessible(method);
754                                        method.invoke(bean, arguments);
755                                }
756                                catch (InvocationTargetException ex) {
757                                        throw ex.getTargetException();
758                                }
759                        }
760                }
761
762                @Nullable
763                private Object[] resolveCachedArguments(@Nullable String beanName) {
764                        Object[] cachedMethodArguments = this.cachedMethodArguments;
765                        if (cachedMethodArguments == null) {
766                                return null;
767                        }
768                        Object[] arguments = new Object[cachedMethodArguments.length];
769                        for (int i = 0; i < arguments.length; i++) {
770                                arguments[i] = resolvedCachedArgument(beanName, cachedMethodArguments[i]);
771                        }
772                        return arguments;
773                }
774        }
775
776
777        /**
778         * DependencyDescriptor variant with a pre-resolved target bean name.
779         */
780        @SuppressWarnings("serial")
781        private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
782
783                private final String shortcut;
784
785                private final Class<?> requiredType;
786
787                public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcut, Class<?> requiredType) {
788                        super(original);
789                        this.shortcut = shortcut;
790                        this.requiredType = requiredType;
791                }
792
793                @Override
794                public Object resolveShortcut(BeanFactory beanFactory) {
795                        return beanFactory.getBean(this.shortcut, this.requiredType);
796                }
797        }
798
799}