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