2828import java .util .List ;
2929import java .util .Locale ;
3030import java .util .Map ;
31+ import java .util .Map .Entry ;
3132import java .util .Set ;
33+ import java .util .function .Predicate ;
3234
3335import org .springframework .aop .scope .ScopedProxyUtils ;
3436import org .springframework .beans .factory .BeanFactory ;
@@ -113,61 +115,90 @@ private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? exten
113115
114116 @ Override
115117 public ConditionOutcome getMatchOutcome (ConditionContext context , AnnotatedTypeMetadata metadata ) {
116- ConditionMessage matchMessage = ConditionMessage . empty ();
118+ ConditionOutcome matchOutcome = ConditionOutcome . match ();
117119 MergedAnnotations annotations = metadata .getAnnotations ();
118120 if (annotations .isPresent (ConditionalOnBean .class )) {
119121 Spec <ConditionalOnBean > spec = new Spec <>(context , metadata , annotations , ConditionalOnBean .class );
120- MatchResult matchResult = getMatchingBeans (context , spec );
121- if (!matchResult .isAllMatched ()) {
122- String reason = createOnBeanNoMatchReason (matchResult );
123- return ConditionOutcome .noMatch (spec .message ().because (reason ));
122+ matchOutcome = evaluateConditionalOnBean (spec , matchOutcome .getConditionMessage ());
123+ if (!matchOutcome .isMatch ()) {
124+ return matchOutcome ;
124125 }
125- matchMessage = spec .message (matchMessage )
126- .found ("bean" , "beans" )
127- .items (Style .QUOTE , matchResult .getNamesOfAllMatches ());
128126 }
129127 if (metadata .isAnnotated (ConditionalOnSingleCandidate .class .getName ())) {
130- Spec <ConditionalOnSingleCandidate > spec = new SingleCandidateSpec (context , metadata , annotations );
131- MatchResult matchResult = getMatchingBeans (context , spec );
132- if (!matchResult .isAllMatched ()) {
133- return ConditionOutcome .noMatch (spec .message ().didNotFind ("any beans" ).atAll ());
134- }
135- Set <String > allBeans = matchResult .getNamesOfAllMatches ();
136- if (allBeans .size () == 1 ) {
137- matchMessage = spec .message (matchMessage ).found ("a single bean" ).items (Style .QUOTE , allBeans );
138- }
139- else {
140- List <String > primaryBeans = getPrimaryBeans (context .getBeanFactory (), allBeans ,
141- spec .getStrategy () == SearchStrategy .ALL );
142- if (primaryBeans .isEmpty ()) {
143- return ConditionOutcome
144- .noMatch (spec .message ().didNotFind ("a primary bean from beans" ).items (Style .QUOTE , allBeans ));
145- }
146- if (primaryBeans .size () > 1 ) {
147- return ConditionOutcome
148- .noMatch (spec .message ().found ("multiple primary beans" ).items (Style .QUOTE , primaryBeans ));
149- }
150- matchMessage = spec .message (matchMessage )
151- .found ("a single primary bean '" + primaryBeans .get (0 ) + "' from beans" )
152- .items (Style .QUOTE , allBeans );
128+ Spec <ConditionalOnSingleCandidate > spec = new SingleCandidateSpec (context , metadata ,
129+ metadata .getAnnotations ());
130+ matchOutcome = evaluateConditionalOnSingleCandidate (spec , matchOutcome .getConditionMessage ());
131+ if (!matchOutcome .isMatch ()) {
132+ return matchOutcome ;
153133 }
154134 }
155135 if (metadata .isAnnotated (ConditionalOnMissingBean .class .getName ())) {
156136 Spec <ConditionalOnMissingBean > spec = new Spec <>(context , metadata , annotations ,
157137 ConditionalOnMissingBean .class );
158- MatchResult matchResult = getMatchingBeans (context , spec );
159- if (matchResult .isAnyMatched ()) {
160- String reason = createOnMissingBeanNoMatchReason (matchResult );
161- return ConditionOutcome .noMatch (spec .message ().because (reason ));
138+ matchOutcome = evaluateConditionalOnMissingBean (spec , matchOutcome .getConditionMessage ());
139+ if (!matchOutcome .isMatch ()) {
140+ return matchOutcome ;
162141 }
163- matchMessage = spec .message (matchMessage ).didNotFind ("any beans" ).atAll ();
164142 }
165- return ConditionOutcome .match (matchMessage );
143+ return matchOutcome ;
144+ }
145+
146+ private ConditionOutcome evaluateConditionalOnBean (Spec <ConditionalOnBean > spec , ConditionMessage matchMessage ) {
147+ MatchResult matchResult = getMatchingBeans (spec );
148+ if (!matchResult .isAllMatched ()) {
149+ String reason = createOnBeanNoMatchReason (matchResult );
150+ return ConditionOutcome .noMatch (spec .message ().because (reason ));
151+ }
152+ return ConditionOutcome .match (spec .message (matchMessage )
153+ .found ("bean" , "beans" )
154+ .items (Style .QUOTE , matchResult .getNamesOfAllMatches ()));
155+ }
156+
157+ private ConditionOutcome evaluateConditionalOnSingleCandidate (Spec <ConditionalOnSingleCandidate > spec ,
158+ ConditionMessage matchMessage ) {
159+ MatchResult matchResult = getMatchingBeans (spec );
160+ if (!matchResult .isAllMatched ()) {
161+ return ConditionOutcome .noMatch (spec .message ().didNotFind ("any beans" ).atAll ());
162+ }
163+ Set <String > allBeans = matchResult .getNamesOfAllMatches ();
164+ if (allBeans .size () == 1 ) {
165+ return ConditionOutcome
166+ .match (spec .message (matchMessage ).found ("a single bean" ).items (Style .QUOTE , allBeans ));
167+ }
168+ Map <String , BeanDefinition > beanDefinitions = getBeanDefinitions (spec .context .getBeanFactory (), allBeans ,
169+ spec .getStrategy () == SearchStrategy .ALL );
170+ List <String > primaryBeans = getPrimaryBeans (beanDefinitions );
171+ if (primaryBeans .size () == 1 ) {
172+ return ConditionOutcome .match (spec .message (matchMessage )
173+ .found ("a single primary bean '" + primaryBeans .get (0 ) + "' from beans" )
174+ .items (Style .QUOTE , allBeans ));
175+ }
176+ if (primaryBeans .size () > 1 ) {
177+ return ConditionOutcome
178+ .noMatch (spec .message ().found ("multiple primary beans" ).items (Style .QUOTE , primaryBeans ));
179+ }
180+ List <String > nonFallbackBeans = getNonFallbackBeans (beanDefinitions );
181+ if (nonFallbackBeans .size () == 1 ) {
182+ return ConditionOutcome .match (spec .message (matchMessage )
183+ .found ("a single non-fallback bean '" + nonFallbackBeans .get (0 ) + "' from beans" )
184+ .items (Style .QUOTE , allBeans ));
185+ }
186+ return ConditionOutcome .noMatch (spec .message ().found ("multiple beans" ).items (Style .QUOTE , allBeans ));
166187 }
167188
168- protected final MatchResult getMatchingBeans (ConditionContext context , Spec <?> spec ) {
169- ClassLoader classLoader = context .getClassLoader ();
170- ConfigurableListableBeanFactory beanFactory = context .getBeanFactory ();
189+ private ConditionOutcome evaluateConditionalOnMissingBean (Spec <ConditionalOnMissingBean > spec ,
190+ ConditionMessage matchMessage ) {
191+ MatchResult matchResult = getMatchingBeans (spec );
192+ if (matchResult .isAnyMatched ()) {
193+ String reason = createOnMissingBeanNoMatchReason (matchResult );
194+ return ConditionOutcome .noMatch (spec .message ().because (reason ));
195+ }
196+ return ConditionOutcome .match (spec .message (matchMessage ).didNotFind ("any beans" ).atAll ());
197+ }
198+
199+ protected final MatchResult getMatchingBeans (Spec <?> spec ) {
200+ ClassLoader classLoader = spec .getContext ().getClassLoader ();
201+ ConfigurableListableBeanFactory beanFactory = spec .getContext ().getBeanFactory ();
171202 boolean considerHierarchy = spec .getStrategy () != SearchStrategy .CURRENT ;
172203 Set <Class <?>> parameterizedContainers = spec .getParameterizedContainers ();
173204 if (spec .getStrategy () == SearchStrategy .ANCESTORS ) {
@@ -373,16 +404,32 @@ private void appendMessageForMatches(StringBuilder reason, Map<String, Collectio
373404 }
374405 }
375406
376- private List <String > getPrimaryBeans (ConfigurableListableBeanFactory beanFactory , Set < String > beanNames ,
377- boolean considerHierarchy ) {
378- List <String > primaryBeans = new ArrayList <>();
407+ private Map <String , BeanDefinition > getBeanDefinitions (ConfigurableListableBeanFactory beanFactory ,
408+ Set < String > beanNames , boolean considerHierarchy ) {
409+ Map <String , BeanDefinition > definitions = new HashMap <>(beanNames . size () );
379410 for (String beanName : beanNames ) {
380411 BeanDefinition beanDefinition = findBeanDefinition (beanFactory , beanName , considerHierarchy );
381- if (beanDefinition != null && beanDefinition .isPrimary ()) {
382- primaryBeans .add (beanName );
412+ definitions .put (beanName , beanDefinition );
413+ }
414+ return definitions ;
415+ }
416+
417+ private List <String > getPrimaryBeans (Map <String , BeanDefinition > beanDefinitions ) {
418+ return getMatchingBeans (beanDefinitions , BeanDefinition ::isPrimary );
419+ }
420+
421+ private List <String > getNonFallbackBeans (Map <String , BeanDefinition > beanDefinitions ) {
422+ return getMatchingBeans (beanDefinitions , Predicate .not (BeanDefinition ::isFallback ));
423+ }
424+
425+ private List <String > getMatchingBeans (Map <String , BeanDefinition > beanDefinitions , Predicate <BeanDefinition > test ) {
426+ List <String > matches = new ArrayList <>();
427+ for (Entry <String , BeanDefinition > namedBeanDefinition : beanDefinitions .entrySet ()) {
428+ if (test .test (namedBeanDefinition .getValue ())) {
429+ matches .add (namedBeanDefinition .getKey ());
383430 }
384431 }
385- return primaryBeans ;
432+ return matches ;
386433 }
387434
388435 private BeanDefinition findBeanDefinition (ConfigurableListableBeanFactory beanFactory , String beanName ,
@@ -420,7 +467,7 @@ private static Set<String> addAll(Set<String> result, String[] additional) {
420467 */
421468 private static class Spec <A extends Annotation > {
422469
423- private final ClassLoader classLoader ;
470+ private final ConditionContext context ;
424471
425472 private final Class <? extends Annotation > annotationType ;
426473
@@ -442,7 +489,7 @@ private static class Spec<A extends Annotation> {
442489 .filter (MergedAnnotationPredicates .unique (MergedAnnotation ::getMetaTypes ))
443490 .collect (MergedAnnotationCollectors .toMultiValueMap (Adapt .CLASS_TO_STRING ));
444491 MergedAnnotation <A > annotation = annotations .get (annotationType );
445- this .classLoader = context . getClassLoader () ;
492+ this .context = context ;
446493 this .annotationType = annotationType ;
447494 this .names = extract (attributes , "name" );
448495 this .annotations = extract (attributes , "annotation" );
@@ -497,7 +544,7 @@ private Set<Class<?>> resolveWhenPossible(Set<String> classNames) {
497544 Set <Class <?>> resolved = new LinkedHashSet <>(classNames .size ());
498545 for (String className : classNames ) {
499546 try {
500- resolved .add (resolve (className , this .classLoader ));
547+ resolved .add (resolve (className , this .context . getClassLoader () ));
501548 }
502549 catch (ClassNotFoundException | NoClassDefFoundError ex ) {
503550 // Ignore
@@ -596,31 +643,35 @@ private SearchStrategy getStrategy() {
596643 return (this .strategy != null ) ? this .strategy : SearchStrategy .ALL ;
597644 }
598645
599- Set <String > getNames () {
646+ private ConditionContext getContext () {
647+ return this .context ;
648+ }
649+
650+ private Set <String > getNames () {
600651 return this .names ;
601652 }
602653
603- Set <String > getTypes () {
654+ protected Set <String > getTypes () {
604655 return this .types ;
605656 }
606657
607- Set <String > getAnnotations () {
658+ private Set <String > getAnnotations () {
608659 return this .annotations ;
609660 }
610661
611- Set <String > getIgnoredTypes () {
662+ private Set <String > getIgnoredTypes () {
612663 return this .ignoredTypes ;
613664 }
614665
615- Set <Class <?>> getParameterizedContainers () {
666+ private Set <Class <?>> getParameterizedContainers () {
616667 return this .parameterizedContainers ;
617668 }
618669
619- ConditionMessage .Builder message () {
670+ private ConditionMessage .Builder message () {
620671 return ConditionMessage .forCondition (this .annotationType , this );
621672 }
622673
623- ConditionMessage .Builder message (ConditionMessage message ) {
674+ private ConditionMessage .Builder message (ConditionMessage message ) {
624675 return message .andCondition (this .annotationType , this );
625676 }
626677
0 commit comments