/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.test.context.junit.jupiter; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Parameter; import java.util.Optional; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.context.ApplicationContext; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.SynthesizingMethodParameter; /** * Collection of utilities related to autowiring of individual method parameters. * * @author Sam Brannen * @since 5.0 * @see #isAutowirable(Parameter) * @see #resolveDependency(Parameter, Class, ApplicationContext) */ abstract class ParameterAutowireUtils { private ParameterAutowireUtils() { /* no-op */ } /** * Determine if the supplied {@link Parameter} can potentially be * autowired from an {@link ApplicationContext}. * <p>Returns {@code true} if the supplied parameter is of type * {@link ApplicationContext} (or a sub-type thereof) or is annotated or * meta-annotated with {@link Autowired @Autowired}, * {@link Qualifier @Qualifier}, or {@link Value @Value}. * @see #resolveDependency(Parameter, Class, ApplicationContext) */ static boolean isAutowirable(Parameter parameter) { return ApplicationContext.class.isAssignableFrom(parameter.getType()) || AnnotatedElementUtils.hasAnnotation(parameter, Autowired.class) || AnnotatedElementUtils.hasAnnotation(parameter, Qualifier.class) || AnnotatedElementUtils.hasAnnotation(parameter, Value.class); } /** * Resolve the dependency for the supplied {@link Parameter} from the * supplied {@link ApplicationContext}. * <p>Provides comprehensive autowiring support for individual method parameters * on par with Spring's dependency injection facilities for autowired fields and * methods, including support for {@link Autowired @Autowired}, * {@link Qualifier @Qualifier}, and {@link Value @Value} with support for property * placeholders and SpEL expressions in {@code @Value} declarations. * <p>The dependency is required unless the parameter is annotated with * {@link Autowired @Autowired} with the {@link Autowired#required required} * flag set to {@code false}. * <p>If an explicit <em>qualifier</em> is not declared, the name of the parameter * will be used as the qualifier for resolving ambiguities. * @param parameter the parameter whose dependency should be resolved * @param containingClass the concrete class that contains the parameter; this may * differ from the class that declares the parameter in that it may be a subclass * thereof, potentially substituting type variables * @param applicationContext the application context from which to resolve the * dependency * @return the resolved object, or {@code null} if none found * @throws BeansException if dependency resolution failed * @see #isAutowirable(Parameter) * @see Autowired#required * @see SynthesizingMethodParameter#forParameter(Parameter) * @see AutowireCapableBeanFactory#resolveDependency(DependencyDescriptor, String) */ static Object resolveDependency(Parameter parameter, Class<?> containingClass, ApplicationContext applicationContext) { boolean required = findMergedAnnotation(parameter, Autowired.class).map(Autowired::required).orElse(true); MethodParameter methodParameter = SynthesizingMethodParameter.forParameter(parameter); DependencyDescriptor descriptor = new DependencyDescriptor(methodParameter, required); descriptor.setContainingClass(containingClass); return applicationContext.getAutowireCapableBeanFactory().resolveDependency(descriptor, null); } private static <A extends Annotation> Optional<A> findMergedAnnotation(AnnotatedElement element, Class<A> annotationType) { return Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(element, annotationType)); } }