Autowiring rejects self references to a factory method on the same bean as well

Issue: SPR-12018
This commit is contained in:
Juergen Hoeller
2014-07-24 12:13:25 +02:00
parent df3b1f2565
commit 496492b2d8
2 changed files with 90 additions and 18 deletions

View File

@@ -1082,7 +1082,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
}
for (String candidateName : candidateNames) {
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
if (!isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
@@ -1107,13 +1107,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
*/
protected String determineAutowireCandidate(Map<String, Object> candidateBeans, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
String primaryCandidate =
determinePrimaryCandidate(candidateBeans, requiredType);
String primaryCandidate = determinePrimaryCandidate(candidateBeans, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
String priorityCandidate =
determineHighestPriorityCandidate(candidateBeans, requiredType);
String priorityCandidate = determineHighestPriorityCandidate(candidateBeans, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
@@ -1240,6 +1238,23 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
(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.
*/

View File

@@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.PostConstruct;
import org.junit.Before;
import org.junit.Test;
@@ -40,6 +41,7 @@ import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DescriptiveResource;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.Assert;
import static org.junit.Assert.*;
@@ -362,10 +364,8 @@ public class ConfigurationClassPostProcessorTests {
@Test
public void genericsBasedInjectionWithWildcardWithExtendsMatch() {
beanFactory.registerBeanDefinition("configClass",
new RootBeanDefinition(WildcardWithExtendsConfiguration.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithExtendsConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
assertSame(beanFactory.getBean("stringRepo"), beanFactory.getBean("repoConsumer"));
}
@@ -373,8 +373,7 @@ public class ConfigurationClassPostProcessorTests {
@Test
public void genericsBasedInjectionWithWildcardWithGenericExtendsMatch() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(WildcardWithGenericExtendsConfiguration.class));
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
pp.postProcessBeanFactory(beanFactory);
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
}
@@ -388,6 +387,18 @@ public class ConfigurationClassPostProcessorTests {
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;
public Bar(Foo foo) {
this.foo = foo;
}
@@ -492,7 +502,6 @@ public class ConfigurationClassPostProcessorTests {
@Bean
public Repository<String> stringRepo() {
return new Repository<String>() {
@Override
public String toString() {
return "Repository<String>";
@@ -503,7 +512,6 @@ public class ConfigurationClassPostProcessorTests {
@Bean
public Repository<Integer> integerRepo() {
return new Repository<Integer>() {
@Override
public String toString() {
return "Repository<Integer>";
@@ -514,7 +522,6 @@ public class ConfigurationClassPostProcessorTests {
@Bean
public Repository<?> genericRepo() {
return new Repository<Object>() {
@Override
public String toString() {
return "Repository<Object>";
@@ -530,7 +537,6 @@ public class ConfigurationClassPostProcessorTests {
@Scope("prototype")
public Repository<String> stringRepo() {
return new Repository<String>() {
@Override
public String toString() {
return "Repository<String>";
@@ -542,7 +548,6 @@ public class ConfigurationClassPostProcessorTests {
@Scope("prototype")
public Repository<Integer> integerRepo() {
return new Repository<Integer>() {
@Override
public String toString() {
return "Repository<Integer>";
@@ -555,7 +560,6 @@ public class ConfigurationClassPostProcessorTests {
@SuppressWarnings("rawtypes")
public Repository genericRepo() {
return new Repository<Object>() {
@Override
public String toString() {
return "Repository<Object>";
@@ -756,4 +760,57 @@ public class ConfigurationClassPostProcessorTests {
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");
}
}
}