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 d35f65532cb..0d1220a90cd 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 @@ -567,15 +567,33 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto public boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException { + return isAutowireCandidate(beanName, descriptor, getAutowireCandidateResolver()); + } + + /** + * Determine whether the specified bean definition qualifies as an autowire candidate, + * to be injected into other beans which declare a dependency of matching type. + * @param beanName the name of the bean definition to check + * @param descriptor the descriptor of the dependency to resolve + * @param resolver the AutowireCandidateResolver to use for the actual resolution algorithm + * @return whether the bean should be considered as autowire candidate + */ + protected boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor, AutowireCandidateResolver resolver) + throws NoSuchBeanDefinitionException { + String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName); if (containsBeanDefinition(beanDefinitionName)) { - return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanDefinitionName), descriptor); + return isAutowireCandidate(beanName, getMergedLocalBeanDefinition(beanDefinitionName), descriptor, resolver); } else if (containsSingleton(beanName)) { - return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor); + return isAutowireCandidate(beanName, new RootBeanDefinition(getType(beanName)), descriptor, resolver); + } + else if (getParentBeanFactory() instanceof DefaultListableBeanFactory) { + // No bean definition found in this factory -> delegate to parent. + return ((DefaultListableBeanFactory) getParentBeanFactory()).isAutowireCandidate(beanName, descriptor, resolver); } else if (getParentBeanFactory() instanceof ConfigurableListableBeanFactory) { - // No bean definition found in this factory -> delegate to parent. + // If no DefaultListableBeanFactory, can't pass the resolver along. return ((ConfigurableListableBeanFactory) getParentBeanFactory()).isAutowireCandidate(beanName, descriptor); } else { @@ -589,9 +607,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto * @param beanName the name of the bean definition to check * @param mbd the merged bean definition to check * @param descriptor the descriptor of the dependency to resolve + * @param resolver the AutowireCandidateResolver to use for the actual resolution algorithm * @return whether the bean should be considered as autowire candidate */ - protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, DependencyDescriptor descriptor) { + protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd, + DependencyDescriptor descriptor, AutowireCandidateResolver resolver) { + String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName); resolveBeanClass(mbd, beanDefinitionName); if (mbd.isFactoryMethodUnique) { @@ -603,7 +624,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd); } } - return getAutowireCandidateResolver().isAutowireCandidate( + return resolver.isAutowireCandidate( new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor); } diff --git a/spring-context/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java b/spring-context/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java index 5271e479157..ea06af95735 100644 --- a/spring-context/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java +++ b/spring-context/src/test/java/org/springframework/beans/factory/xml/QualifierAnnotationTests.java @@ -16,14 +16,12 @@ package org.springframework.beans.factory.xml; -import static java.lang.String.format; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Properties; -import static org.junit.Assert.*; import org.junit.Test; import org.springframework.beans.factory.BeanCreationException; @@ -31,8 +29,13 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver; +import org.springframework.beans.factory.support.AutowireCandidateQualifier; import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.support.StaticApplicationContext; + +import static java.lang.String.format; +import static org.junit.Assert.*; import static org.springframework.util.ClassUtils.*; /** @@ -74,6 +77,31 @@ public final class QualifierAnnotationTests { assertEquals("Larry", person.getName()); } + @Test + public void testQualifiedByParentValue() { + StaticApplicationContext parent = new StaticApplicationContext(); + GenericBeanDefinition parentLarry = new GenericBeanDefinition(); + parentLarry.setBeanClass(Person.class); + parentLarry.getPropertyValues().add("name", "ParentLarry"); + parentLarry.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "parentLarry")); + parent.registerBeanDefinition("someLarry", parentLarry); + GenericBeanDefinition otherLarry = new GenericBeanDefinition(); + otherLarry.setBeanClass(Person.class); + otherLarry.getPropertyValues().add("name", "OtherLarry"); + otherLarry.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "otherLarry")); + parent.registerBeanDefinition("someOtherLarry", otherLarry); + parent.refresh(); + + StaticApplicationContext context = new StaticApplicationContext(parent); + BeanDefinitionReader reader = new XmlBeanDefinitionReader(context); + reader.loadBeanDefinitions(CONFIG_LOCATION); + context.registerSingleton("testBean", QualifiedByParentValueTestBean.class); + context.refresh(); + QualifiedByParentValueTestBean testBean = (QualifiedByParentValueTestBean) context.getBean("testBean"); + Person person = testBean.getLarry(); + assertEquals("ParentLarry", person.getName()); + } + @Test public void testQualifiedByBeanName() { StaticApplicationContext context = new StaticApplicationContext(); @@ -222,6 +250,17 @@ public final class QualifierAnnotationTests { } + private static class QualifiedByParentValueTestBean { + + @Autowired @Qualifier("parentLarry") + private Person larry; + + public Person getLarry() { + return larry; + } + } + + private static class QualifiedByBeanNameTestBean { @Autowired @Qualifier("larryBean")