Autowiring rejects self references to a factory method on the same bean as well
Issue: SPR-12018
This commit is contained in:
@@ -1082,7 +1082,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String candidateName : candidateNames) {
|
for (String candidateName : candidateNames) {
|
||||||
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
|
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
|
||||||
result.put(candidateName, getBean(candidateName));
|
result.put(candidateName, getBean(candidateName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1107,13 +1107,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
*/
|
*/
|
||||||
protected String determineAutowireCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {
|
protected String determineAutowireCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {
|
||||||
Class<?> requiredType = descriptor.getDependencyType();
|
Class<?> requiredType = descriptor.getDependencyType();
|
||||||
String primaryCandidate =
|
String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
|
||||||
determinePrimaryCandidate(candidateBeans, requiredType);
|
|
||||||
if (primaryCandidate != null) {
|
if (primaryCandidate != null) {
|
||||||
return primaryCandidate;
|
return primaryCandidate;
|
||||||
}
|
}
|
||||||
String priorityCandidate =
|
String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
|
||||||
determineHighestPriorityCandidate(candidateBeans, requiredType);
|
|
||||||
if (priorityCandidate != null) {
|
if (priorityCandidate != null) {
|
||||||
return priorityCandidate;
|
return priorityCandidate;
|
||||||
}
|
}
|
||||||
@@ -1240,6 +1238,23 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||||||
(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
|
(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the given beanName/candidateName pair indicates a self reference,
|
||||||
|
* i.e. whether the candidate points back to the original bean or to a factory method
|
||||||
|
* on the original bean.
|
||||||
|
*/
|
||||||
|
private boolean isSelfReference(String beanName, String candidateName) {
|
||||||
|
if (beanName.equals(candidateName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (candidateName != null && containsBeanDefinition(candidateName)) {
|
||||||
|
if (beanName.equals(getMergedLocalBeanDefinition(candidateName).getFactoryBeanName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raise a NoSuchBeanDefinitionException for an unresolvable dependency.
|
* Raise a NoSuchBeanDefinitionException for an unresolvable dependency.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -40,6 +41,7 @@ import org.springframework.core.env.StandardEnvironment;
|
|||||||
import org.springframework.core.io.DescriptiveResource;
|
import org.springframework.core.io.DescriptiveResource;
|
||||||
import org.springframework.tests.sample.beans.ITestBean;
|
import org.springframework.tests.sample.beans.ITestBean;
|
||||||
import org.springframework.tests.sample.beans.TestBean;
|
import org.springframework.tests.sample.beans.TestBean;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
@@ -362,10 +364,8 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void genericsBasedInjectionWithWildcardWithExtendsMatch() {
|
public void genericsBasedInjectionWithWildcardWithExtendsMatch() {
|
||||||
beanFactory.registerBeanDefinition("configClass",
|
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithExtendsConfiguration.class));
|
||||||
new RootBeanDefinition(WildcardWithExtendsConfiguration.class));
|
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
|
||||||
pp.postProcessBeanFactory(beanFactory);
|
|
||||||
|
|
||||||
assertSame(beanFactory.getBean("stringRepo"), beanFactory.getBean("repoConsumer"));
|
assertSame(beanFactory.getBean("stringRepo"), beanFactory.getBean("repoConsumer"));
|
||||||
}
|
}
|
||||||
@@ -373,8 +373,7 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
@Test
|
@Test
|
||||||
public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
|
public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
|
||||||
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class));
|
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class));
|
||||||
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
|
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||||
pp.postProcessBeanFactory(beanFactory);
|
|
||||||
|
|
||||||
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
|
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
|
||||||
}
|
}
|
||||||
@@ -388,6 +387,18 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
assertNotNull(simpleComponent);
|
assertNotNull(simpleComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
|
||||||
|
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||||
|
bpp.setBeanFactory(beanFactory);
|
||||||
|
beanFactory.addBeanPostProcessor(bpp);
|
||||||
|
beanFactory.addBeanPostProcessor(new CommonAnnotationBeanPostProcessor());
|
||||||
|
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(ConcreteConfig.class));
|
||||||
|
beanFactory.registerBeanDefinition("serviceBeanProvider", new RootBeanDefinition(ServiceBeanProvider.class));
|
||||||
|
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
|
||||||
|
beanFactory.preInstantiateSingletons();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -412,7 +423,6 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
|
|
||||||
final Foo foo;
|
final Foo foo;
|
||||||
|
|
||||||
|
|
||||||
public Bar(Foo foo) {
|
public Bar(Foo foo) {
|
||||||
this.foo = foo;
|
this.foo = foo;
|
||||||
}
|
}
|
||||||
@@ -492,7 +502,6 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
@Bean
|
@Bean
|
||||||
public Repository<String> stringRepo() {
|
public Repository<String> stringRepo() {
|
||||||
return new Repository<String>() {
|
return new Repository<String>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Repository<String>";
|
return "Repository<String>";
|
||||||
@@ -503,7 +512,6 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
@Bean
|
@Bean
|
||||||
public Repository<Integer> integerRepo() {
|
public Repository<Integer> integerRepo() {
|
||||||
return new Repository<Integer>() {
|
return new Repository<Integer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Repository<Integer>";
|
return "Repository<Integer>";
|
||||||
@@ -514,7 +522,6 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
@Bean
|
@Bean
|
||||||
public Repository<?> genericRepo() {
|
public Repository<?> genericRepo() {
|
||||||
return new Repository<Object>() {
|
return new Repository<Object>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Repository<Object>";
|
return "Repository<Object>";
|
||||||
@@ -530,7 +537,6 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
public Repository<String> stringRepo() {
|
public Repository<String> stringRepo() {
|
||||||
return new Repository<String>() {
|
return new Repository<String>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Repository<String>";
|
return "Repository<String>";
|
||||||
@@ -542,7 +548,6 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
public Repository<Integer> integerRepo() {
|
public Repository<Integer> integerRepo() {
|
||||||
return new Repository<Integer>() {
|
return new Repository<Integer>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Repository<Integer>";
|
return "Repository<Integer>";
|
||||||
@@ -555,7 +560,6 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public Repository genericRepo() {
|
public Repository genericRepo() {
|
||||||
return new Repository<Object>() {
|
return new Repository<Object>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Repository<Object>";
|
return "Repository<Object>";
|
||||||
@@ -756,4 +760,57 @@ public class ConfigurationClassPostProcessorTests {
|
|||||||
MetaComponentScanConfigurationWithAttributeOverridesClass {
|
MetaComponentScanConfigurationWithAttributeOverridesClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ServiceBean {
|
||||||
|
|
||||||
|
private final String parameter;
|
||||||
|
|
||||||
|
public ServiceBean(String parameter) {
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParameter() {
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static abstract class AbstractConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServiceBean serviceBean() {
|
||||||
|
return provider().getServiceBean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServiceBeanProvider provider() {
|
||||||
|
return new ServiceBeanProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public static class ConcreteConfig extends AbstractConfig {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ServiceBeanProvider provider;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Override
|
||||||
|
public ServiceBeanProvider provider() {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void validate() {
|
||||||
|
Assert.notNull(provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Primary
|
||||||
|
public static class ServiceBeanProvider {
|
||||||
|
|
||||||
|
public ServiceBean getServiceBean() {
|
||||||
|
return new ServiceBean("message");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user