diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java index 948b8d01f2..6414cc407b 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java @@ -94,7 +94,8 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit return ConditionOutcome.noMatch( "@ConditionalOnSingleCandidate " + spec + " found no beans"); } - else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matching)) { + else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matching, + spec.getStrategy() == SearchStrategy.ALL)) { return ConditionOutcome.noMatch("@ConditionalOnSingleCandidate " + spec + " found no primary candidate amongst the" + " following " + matching); @@ -222,16 +223,19 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit } private boolean hasSingleAutowireCandidate( - ConfigurableListableBeanFactory beanFactory, List beanNames) { + ConfigurableListableBeanFactory beanFactory, List beanNames, + boolean considerHierarchy) { return (beanNames.size() == 1 - || getPrimaryBeans(beanFactory, beanNames).size() == 1); + || getPrimaryBeans(beanFactory, beanNames, considerHierarchy) + .size() == 1); } private List getPrimaryBeans(ConfigurableListableBeanFactory beanFactory, - List beanNames) { + List beanNames, boolean considerHierarchy) { List primaryBeans = new ArrayList(); for (String beanName : beanNames) { - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); + BeanDefinition beanDefinition = findBeanDefinition(beanFactory, beanName, + considerHierarchy); if (beanDefinition != null && beanDefinition.isPrimary()) { primaryBeans.add(beanName); } @@ -239,6 +243,20 @@ class OnBeanCondition extends SpringBootCondition implements ConfigurationCondit return primaryBeans; } + private BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory, + String beanName, boolean considerHierarchy) { + if (beanFactory.containsBeanDefinition(beanName)) { + return beanFactory.getBeanDefinition(beanName); + } + if (considerHierarchy && beanFactory + .getParentBeanFactory() instanceof ConfigurableListableBeanFactory) { + return findBeanDefinition(((ConfigurableListableBeanFactory) beanFactory + .getParentBeanFactory()), beanName, considerHierarchy); + } + return null; + + } + private static class BeanSearchSpec { private final Class annotationType; diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java index 27ff00a11a..4d610e7f21 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java @@ -33,6 +33,7 @@ import static org.hamcrest.CoreMatchers.isA; * Tests for {@link ConditionalOnSingleCandidate}. * * @author Stephane Nicoll + * @author Andy Wilkinson */ public class ConditionalOnSingleCandidateTests { @@ -101,6 +102,22 @@ public class ConditionalOnSingleCandidateTests { load(OnBeanSingleCandidateNoTypeConfiguration.class); } + @Test + public void singleCandidateMultipleCandidatesInContextHierarchy() { + load(FooPrimaryConfiguration.class, BarConfiguration.class); + AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext(); + child.setParent(this.context); + child.register(OnBeanSingleCandidateConfiguration.class); + try { + child.refresh(); + assertThat(child.containsBean("baz")).isTrue(); + assertThat(child.getBean("baz")).isEqualTo("foo"); + } + finally { + child.close(); + } + } + private void load(Class... classes) { this.context.register(classes); this.context.refresh();