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.lang.annotation.Annotation;
020import java.lang.reflect.AnnotatedElement;
021import java.lang.reflect.Constructor;
022import java.lang.reflect.Executable;
023import java.lang.reflect.Parameter;
024
025import org.springframework.beans.BeansException;
026import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
027import org.springframework.beans.factory.config.DependencyDescriptor;
028import org.springframework.core.MethodParameter;
029import org.springframework.core.annotation.AnnotatedElementUtils;
030import org.springframework.core.annotation.SynthesizingMethodParameter;
031import org.springframework.lang.Nullable;
032import org.springframework.util.Assert;
033import org.springframework.util.ClassUtils;
034
035/**
036 * Public delegate for resolving autowirable parameters on externally managed
037 * constructors and methods.
038 *
039 * @author Sam Brannen
040 * @author Juergen Hoeller
041 * @since 5.2
042 * @see #isAutowirable
043 * @see #resolveDependency
044 */
045public final class ParameterResolutionDelegate {
046
047        private static final AnnotatedElement EMPTY_ANNOTATED_ELEMENT = new AnnotatedElement() {
048                @Override
049                @Nullable
050                public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
051                        return null;
052                }
053                @Override
054                public Annotation[] getAnnotations() {
055                        return new Annotation[0];
056                }
057                @Override
058                public Annotation[] getDeclaredAnnotations() {
059                        return new Annotation[0];
060                }
061        };
062
063
064        private ParameterResolutionDelegate() {
065        }
066
067
068        /**
069         * Determine if the supplied {@link Parameter} can <em>potentially</em> be
070         * autowired from an {@link AutowireCapableBeanFactory}.
071         * <p>Returns {@code true} if the supplied parameter is annotated or
072         * meta-annotated with {@link Autowired @Autowired},
073         * {@link Qualifier @Qualifier}, or {@link Value @Value}.
074         * <p>Note that {@link #resolveDependency} may still be able to resolve the
075         * dependency for the supplied parameter even if this method returns {@code false}.
076         * @param parameter the parameter whose dependency should be autowired
077         * (must not be {@code null})
078         * @param parameterIndex the index of the parameter in the constructor or method
079         * that declares the parameter
080         * @see #resolveDependency
081         */
082        public static boolean isAutowirable(Parameter parameter, int parameterIndex) {
083                Assert.notNull(parameter, "Parameter must not be null");
084                AnnotatedElement annotatedParameter = getEffectiveAnnotatedParameter(parameter, parameterIndex);
085                return (AnnotatedElementUtils.hasAnnotation(annotatedParameter, Autowired.class) ||
086                                AnnotatedElementUtils.hasAnnotation(annotatedParameter, Qualifier.class) ||
087                                AnnotatedElementUtils.hasAnnotation(annotatedParameter, Value.class));
088        }
089
090        /**
091         * Resolve the dependency for the supplied {@link Parameter} from the
092         * supplied {@link AutowireCapableBeanFactory}.
093         * <p>Provides comprehensive autowiring support for individual method parameters
094         * on par with Spring's dependency injection facilities for autowired fields and
095         * methods, including support for {@link Autowired @Autowired},
096         * {@link Qualifier @Qualifier}, and {@link Value @Value} with support for property
097         * placeholders and SpEL expressions in {@code @Value} declarations.
098         * <p>The dependency is required unless the parameter is annotated or meta-annotated
099         * with {@link Autowired @Autowired} with the {@link Autowired#required required}
100         * flag set to {@code false}.
101         * <p>If an explicit <em>qualifier</em> is not declared, the name of the parameter
102         * will be used as the qualifier for resolving ambiguities.
103         * @param parameter the parameter whose dependency should be resolved (must not be
104         * {@code null})
105         * @param parameterIndex the index of the parameter in the constructor or method
106         * that declares the parameter
107         * @param containingClass the concrete class that contains the parameter; this may
108         * differ from the class that declares the parameter in that it may be a subclass
109         * thereof, potentially substituting type variables (must not be {@code null})
110         * @param beanFactory the {@code AutowireCapableBeanFactory} from which to resolve
111         * the dependency (must not be {@code null})
112         * @return the resolved object, or {@code null} if none found
113         * @throws BeansException if dependency resolution failed
114         * @see #isAutowirable
115         * @see Autowired#required
116         * @see SynthesizingMethodParameter#forExecutable(Executable, int)
117         * @see AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String)
118         */
119        @Nullable
120        public static Object resolveDependency(
121                        Parameter parameter, int parameterIndex, Class<?> containingClass, AutowireCapableBeanFactory beanFactory)
122                        throws BeansException {
123
124                Assert.notNull(parameter, "Parameter must not be null");
125                Assert.notNull(containingClass, "Containing class must not be null");
126                Assert.notNull(beanFactory, "AutowireCapableBeanFactory must not be null");
127
128                AnnotatedElement annotatedParameter = getEffectiveAnnotatedParameter(parameter, parameterIndex);
129                Autowired autowired = AnnotatedElementUtils.findMergedAnnotation(annotatedParameter, Autowired.class);
130                boolean required = (autowired == null || autowired.required());
131
132                MethodParameter methodParameter = SynthesizingMethodParameter.forExecutable(
133                                parameter.getDeclaringExecutable(), parameterIndex);
134                DependencyDescriptor descriptor = new DependencyDescriptor(methodParameter, required);
135                descriptor.setContainingClass(containingClass);
136                return beanFactory.resolveDependency(descriptor, null);
137        }
138
139        /**
140         * Due to a bug in {@code javac} on JDK versions prior to JDK 9, looking up
141         * annotations directly on a {@link Parameter} will fail for inner class
142         * constructors.
143         * <h4>Bug in javac in JDK &lt; 9</h4>
144         * <p>The parameter annotations array in the compiled byte code excludes an entry
145         * for the implicit <em>enclosing instance</em> parameter for an inner class
146         * constructor.
147         * <h4>Workaround</h4>
148         * <p>This method provides a workaround for this off-by-one error by allowing the
149         * caller to access annotations on the preceding {@link Parameter} object (i.e.,
150         * {@code index - 1}). If the supplied {@code index} is zero, this method returns
151         * an empty {@code AnnotatedElement}.
152         * <h4>WARNING</h4>
153         * <p>The {@code AnnotatedElement} returned by this method should never be cast and
154         * treated as a {@code Parameter} since the metadata (e.g., {@link Parameter#getName()},
155         * {@link Parameter#getType()}, etc.) will not match those for the declared parameter
156         * at the given index in an inner class constructor.
157         * @return the supplied {@code parameter} or the <em>effective</em> {@code Parameter}
158         * if the aforementioned bug is in effect
159         */
160        private static AnnotatedElement getEffectiveAnnotatedParameter(Parameter parameter, int index) {
161                Executable executable = parameter.getDeclaringExecutable();
162                if (executable instanceof Constructor && ClassUtils.isInnerClass(executable.getDeclaringClass()) &&
163                                executable.getParameterAnnotations().length == executable.getParameterCount() - 1) {
164                        // Bug in javac in JDK <9: annotation array excludes enclosing instance parameter
165                        // for inner classes, so access it with the actual parameter index lowered by 1
166                        return (index == 0 ? EMPTY_ANNOTATED_ELEMENT : executable.getParameters()[index - 1]);
167                }
168                return parameter;
169        }
170
171}