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 < 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}