Skip to content

Commit a5c6b09

Browse files
committed
Consider ancestors when finding primary beans for ConditionalOnSingleCandidate
Closes gh-6559
1 parent 75c1e50 commit a5c6b09

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ public ConditionOutcome getMatchOutcome(ConditionContext context,
9999
return ConditionOutcome.noMatch(
100100
"@ConditionalOnSingleCandidate " + spec + " found no beans");
101101
}
102-
else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matching)) {
102+
else if (!hasSingleAutowireCandidate(context.getBeanFactory(), matching,
103+
spec.getStrategy() == SearchStrategy.ALL)) {
103104
return ConditionOutcome.noMatch("@ConditionalOnSingleCandidate " + spec
104105
+ " found no primary candidate amongst the" + " following "
105106
+ matching);
@@ -225,23 +226,40 @@ private String[] getBeanNamesForAnnotation(
225226
}
226227

227228
private boolean hasSingleAutowireCandidate(
228-
ConfigurableListableBeanFactory beanFactory, List<String> beanNames) {
229+
ConfigurableListableBeanFactory beanFactory, List<String> beanNames,
230+
boolean considerHierarchy) {
229231
return (beanNames.size() == 1
230-
|| getPrimaryBeans(beanFactory, beanNames).size() == 1);
232+
|| getPrimaryBeans(beanFactory, beanNames, considerHierarchy)
233+
.size() == 1);
231234
}
232235

233236
private List<String> getPrimaryBeans(ConfigurableListableBeanFactory beanFactory,
234-
List<String> beanNames) {
237+
List<String> beanNames, boolean considerHierarchy) {
235238
List<String> primaryBeans = new ArrayList<String>();
236239
for (String beanName : beanNames) {
237-
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
240+
BeanDefinition beanDefinition = findBeanDefinition(beanFactory, beanName,
241+
considerHierarchy);
238242
if (beanDefinition != null && beanDefinition.isPrimary()) {
239243
primaryBeans.add(beanName);
240244
}
241245
}
242246
return primaryBeans;
243247
}
244248

249+
private BeanDefinition findBeanDefinition(ConfigurableListableBeanFactory beanFactory,
250+
String beanName, boolean considerHierarchy) {
251+
if (beanFactory.containsBeanDefinition(beanName)) {
252+
return beanFactory.getBeanDefinition(beanName);
253+
}
254+
if (considerHierarchy && beanFactory
255+
.getParentBeanFactory() instanceof ConfigurableListableBeanFactory) {
256+
return findBeanDefinition(((ConfigurableListableBeanFactory) beanFactory
257+
.getParentBeanFactory()), beanName, considerHierarchy);
258+
}
259+
return null;
260+
261+
}
262+
245263
private static class BeanSearchSpec {
246264

247265
private final Class<?> annotationType;

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnSingleCandidateTests.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2015 the original author or authors.
2+
* Copyright 2012-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
3535
* Tests for {@link ConditionalOnSingleCandidate}.
3636
*
3737
* @author Stephane Nicoll
38+
* @author Andy Wilkinson
3839
*/
3940
public class ConditionalOnSingleCandidateTests {
4041

@@ -103,6 +104,22 @@ public void invalidAnnotationNoType() {
103104
load(OnBeanSingleCandidateNoTypeConfiguration.class);
104105
}
105106

107+
@Test
108+
public void singleCandidateMultipleCandidatesInContextHierarchy() {
109+
load(FooPrimaryConfiguration.class, BarConfiguration.class);
110+
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
111+
child.setParent(this.context);
112+
child.register(OnBeanSingleCandidateConfiguration.class);
113+
try {
114+
child.refresh();
115+
assertTrue(child.containsBean("baz"));
116+
assertEquals("foo", child.getBean("baz"));
117+
}
118+
finally {
119+
child.close();
120+
}
121+
}
122+
106123
private void load(Class<?>... classes) {
107124
this.context.register(classes);
108125
this.context.refresh();

0 commit comments

Comments
 (0)