From dcb83c2dafb8016adc66849a4cacf6a734e03195 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 24 Jul 2014 12:13:25 +0200 Subject: [PATCH] Autowiring rejects self references to a factory method on the same bean as well Issue: SPR-12018 (cherry picked from commit 496492b) --- .../support/DefaultListableBeanFactory.java | 13 ++- .../ConfigurationClassPostProcessorTests.java | 83 ++++++++++++++++--- 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 024a732b85..5c347b3dfb 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -1014,7 +1014,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)); } } @@ -1092,6 +1092,17 @@ 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) { + return (beanName != null && candidateName != null && + (beanName.equals(candidateName) || (containsBeanDefinition(candidateName) && + beanName.equals(getMergedLocalBeanDefinition(candidateName).getFactoryBeanName())))); + } + /** * Raise a NoSuchBeanDefinitionException for an unresolvable dependency. */ diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java index 549584f3f4..278f0499b7 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java @@ -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 stringRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -503,7 +512,6 @@ public class ConfigurationClassPostProcessorTests { @Bean public Repository integerRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -514,7 +522,6 @@ public class ConfigurationClassPostProcessorTests { @Bean public Repository genericRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -530,7 +537,6 @@ public class ConfigurationClassPostProcessorTests { @Scope("prototype") public Repository stringRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -542,7 +548,6 @@ public class ConfigurationClassPostProcessorTests { @Scope("prototype") public Repository integerRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -555,7 +560,6 @@ public class ConfigurationClassPostProcessorTests { @SuppressWarnings("rawtypes") public Repository genericRepo() { return new Repository() { - @Override public String toString() { return "Repository"; @@ -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"); + } + } } +