Browse Source

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

Issue: SPR-12018
pull/602/head
Juergen Hoeller 12 years ago
parent
commit
496492b2d8
  1. 25
      spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java
  2. 83
      spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java

25
spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

@ -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.
*/ */

83
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.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");
}
}
}

Loading…
Cancel
Save