From a5c6b0954d2929578a43be1f844d017e33cd32c3 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 26 Aug 2016 17:29:47 +0100 Subject: [PATCH] Consider ancestors when finding primary beans for ConditionalOnSingleCandidate Closes gh-6559 --- .../condition/OnBeanCondition.java | 28 +++++++++++++++---- .../ConditionalOnSingleCandidateTests.java | 19 ++++++++++++- 2 files changed, 41 insertions(+), 6 deletions(-) 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 49d0ce2ffb..1ec9a44aed 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 @@ -99,7 +99,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); @@ -225,16 +226,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); } @@ -242,6 +246,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 d3031b597b..d8a20c5a89 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,7 @@ import static org.junit.Assert.assertTrue; * Tests for {@link ConditionalOnSingleCandidate}. * * @author Stephane Nicoll + * @author Andy Wilkinson */ public class ConditionalOnSingleCandidateTests { @@ -103,6 +104,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(); + assertTrue(child.containsBean("baz")); + assertEquals("foo", child.getBean("baz")); + } + finally { + child.close(); + } + } + private void load(Class... classes) { this.context.register(classes); this.context.refresh();