Current InjectionPoint/DependencyDescriptor as factory method argument
Issue: SPR-14033
This commit is contained in:
parent
2153d88706
commit
a95bf6e0fc
|
|
@ -47,6 +47,7 @@ import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueH
|
||||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||||
import org.springframework.core.GenericTypeResolver;
|
import org.springframework.core.GenericTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.core.NamedThreadLocal;
|
||||||
import org.springframework.core.ParameterNameDiscoverer;
|
import org.springframework.core.ParameterNameDiscoverer;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.MethodInvoker;
|
import org.springframework.util.MethodInvoker;
|
||||||
|
|
@ -69,6 +70,9 @@ import org.springframework.util.StringUtils;
|
||||||
*/
|
*/
|
||||||
class ConstructorResolver {
|
class ConstructorResolver {
|
||||||
|
|
||||||
|
private static final NamedThreadLocal<InjectionPoint> currentInjectionPoint =
|
||||||
|
new NamedThreadLocal<InjectionPoint>("Current injection point");
|
||||||
|
|
||||||
private final AbstractAutowireCapableBeanFactory beanFactory;
|
private final AbstractAutowireCapableBeanFactory beanFactory;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -820,11 +824,31 @@ class ConstructorResolver {
|
||||||
protected Object resolveAutowiredArgument(
|
protected Object resolveAutowiredArgument(
|
||||||
MethodParameter param, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) {
|
MethodParameter param, String beanName, Set<String> autowiredBeanNames, TypeConverter typeConverter) {
|
||||||
|
|
||||||
|
if (InjectionPoint.class.isAssignableFrom(param.getParameterType())) {
|
||||||
|
InjectionPoint injectionPoint = currentInjectionPoint.get();
|
||||||
|
if (injectionPoint == null) {
|
||||||
|
throw new IllegalStateException("No current InjectionPoint available for " + param);
|
||||||
|
}
|
||||||
|
return injectionPoint;
|
||||||
|
}
|
||||||
return this.beanFactory.resolveDependency(
|
return this.beanFactory.resolveDependency(
|
||||||
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
|
new DependencyDescriptor(param, true), beanName, autowiredBeanNames, typeConverter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static InjectionPoint setCurrentInjectionPoint(InjectionPoint injectionPoint) {
|
||||||
|
InjectionPoint old = currentInjectionPoint.get();
|
||||||
|
if (injectionPoint != null) {
|
||||||
|
currentInjectionPoint.set(injectionPoint);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentInjectionPoint.remove();
|
||||||
|
}
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private inner class for holding argument combinations.
|
* Private inner class for holding argument combinations.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||||
import org.springframework.beans.factory.CannotLoadBeanClassException;
|
import org.springframework.beans.factory.CannotLoadBeanClassException;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.ObjectFactory;
|
import org.springframework.beans.factory.ObjectFactory;
|
||||||
|
|
@ -1042,6 +1043,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
return multipleBeans;
|
return multipleBeans;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
|
||||||
|
try {
|
||||||
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
|
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
|
||||||
if (matchingBeans.isEmpty()) {
|
if (matchingBeans.isEmpty()) {
|
||||||
if (descriptor.isRequired()) {
|
if (descriptor.isRequired()) {
|
||||||
|
|
@ -1074,6 +1077,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
}
|
}
|
||||||
return entry.getValue();
|
return entry.getValue();
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Object resolveMultipleBeans(DependencyDescriptor descriptor, String beanName,
|
private Object resolveMultipleBeans(DependencyDescriptor descriptor, String beanName,
|
||||||
Set<String> autowiredBeanNames, TypeConverter typeConverter) {
|
Set<String> autowiredBeanNames, TypeConverter typeConverter) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2014 the original author or authors.
|
* Copyright 2002-2016 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -27,8 +27,13 @@ import org.junit.Test;
|
||||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.ListableBeanFactory;
|
import org.springframework.beans.factory.ListableBeanFactory;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
|
||||||
import org.springframework.beans.factory.annotation.Required;
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
@ -36,6 +41,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||||
import org.springframework.beans.factory.config.ListFactoryBean;
|
import org.springframework.beans.factory.config.ListFactoryBean;
|
||||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||||
|
|
@ -71,7 +77,7 @@ public class ConfigurationClassProcessingTests {
|
||||||
* When complete, the factory is ready to service requests for any {@link Bean} methods
|
* When complete, the factory is ready to service requests for any {@link Bean} methods
|
||||||
* declared by <var>configClasses</var>.
|
* declared by <var>configClasses</var>.
|
||||||
*/
|
*/
|
||||||
private ListableBeanFactory initBeanFactory(Class<?>... configClasses) {
|
private DefaultListableBeanFactory initBeanFactory(Class<?>... configClasses) {
|
||||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||||
for (Class<?> configClass : configClasses) {
|
for (Class<?> configClass : configClasses) {
|
||||||
String configBeanName = configClass.getName();
|
String configBeanName = configClass.getName();
|
||||||
|
|
@ -202,6 +208,20 @@ public class ConfigurationClassProcessingTests {
|
||||||
assertNotSame(bar.getSpouse(), baz);
|
assertNotSame(bar.getSpouse(), baz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void configurationWithAdaptivePrototypes() {
|
||||||
|
DefaultListableBeanFactory factory =
|
||||||
|
initBeanFactory(ConfigWithPrototypeBean.class, AdaptiveInjectionPoints.class);
|
||||||
|
AutowiredAnnotationBeanPostProcessor aabpp = new AutowiredAnnotationBeanPostProcessor();
|
||||||
|
aabpp.setBeanFactory(factory);
|
||||||
|
factory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
||||||
|
factory.addBeanPostProcessor(aabpp);
|
||||||
|
|
||||||
|
AdaptiveInjectionPoints adaptive = factory.getBean(AdaptiveInjectionPoints.class);
|
||||||
|
assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName());
|
||||||
|
assertEquals("adaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void configurationWithPostProcessor() {
|
public void configurationWithPostProcessor() {
|
||||||
AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext();
|
||||||
|
|
@ -324,6 +344,26 @@ public class ConfigurationClassProcessingTests {
|
||||||
public TestBean baz() {
|
public TestBean baz() {
|
||||||
return new TestBean("baz");
|
return new TestBean("baz");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean @Scope("prototype")
|
||||||
|
public TestBean adaptive1(InjectionPoint ip) {
|
||||||
|
return new TestBean(ip.getMember().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean @Scope("prototype")
|
||||||
|
public TestBean adaptive2(DependencyDescriptor dd) {
|
||||||
|
return new TestBean(dd.getMember().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class AdaptiveInjectionPoints {
|
||||||
|
|
||||||
|
@Autowired @Qualifier("adaptive1")
|
||||||
|
public TestBean adaptiveInjectionPoint1;
|
||||||
|
|
||||||
|
@Autowired @Qualifier("adaptive2")
|
||||||
|
public TestBean adaptiveInjectionPoint2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue