28
28
import java .util .List ;
29
29
import java .util .Locale ;
30
30
import java .util .Map ;
31
+ import java .util .Map .Entry ;
31
32
import java .util .Set ;
33
+ import java .util .function .Predicate ;
32
34
33
35
import org .springframework .aop .scope .ScopedProxyUtils ;
34
36
import org .springframework .beans .factory .BeanFactory ;
@@ -113,61 +115,90 @@ private ConditionOutcome getOutcome(Set<String> requiredBeanTypes, Class<? exten
113
115
114
116
@ Override
115
117
public ConditionOutcome getMatchOutcome (ConditionContext context , AnnotatedTypeMetadata metadata ) {
116
- ConditionMessage matchMessage = ConditionMessage . empty ();
118
+ ConditionOutcome matchOutcome = ConditionOutcome . match ();
117
119
MergedAnnotations annotations = metadata .getAnnotations ();
118
120
if (annotations .isPresent (ConditionalOnBean .class )) {
119
121
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 ;
124
125
}
125
- matchMessage = spec .message (matchMessage )
126
- .found ("bean" , "beans" )
127
- .items (Style .QUOTE , matchResult .getNamesOfAllMatches ());
128
126
}
129
127
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 ;
153
133
}
154
134
}
155
135
if (metadata .isAnnotated (ConditionalOnMissingBean .class .getName ())) {
156
136
Spec <ConditionalOnMissingBean > spec = new Spec <>(context , metadata , annotations ,
157
137
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 ;
162
141
}
163
- matchMessage = spec .message (matchMessage ).didNotFind ("any beans" ).atAll ();
164
142
}
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 ));
166
187
}
167
188
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 ();
171
202
boolean considerHierarchy = spec .getStrategy () != SearchStrategy .CURRENT ;
172
203
Set <Class <?>> parameterizedContainers = spec .getParameterizedContainers ();
173
204
if (spec .getStrategy () == SearchStrategy .ANCESTORS ) {
@@ -373,16 +404,32 @@ private void appendMessageForMatches(StringBuilder reason, Map<String, Collectio
373
404
}
374
405
}
375
406
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 () );
379
410
for (String beanName : beanNames ) {
380
411
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 ());
383
430
}
384
431
}
385
- return primaryBeans ;
432
+ return matches ;
386
433
}
387
434
388
435
private BeanDefinition findBeanDefinition (ConfigurableListableBeanFactory beanFactory , String beanName ,
@@ -420,7 +467,7 @@ private static Set<String> addAll(Set<String> result, String[] additional) {
420
467
*/
421
468
private static class Spec <A extends Annotation > {
422
469
423
- private final ClassLoader classLoader ;
470
+ private final ConditionContext context ;
424
471
425
472
private final Class <? extends Annotation > annotationType ;
426
473
@@ -442,7 +489,7 @@ private static class Spec<A extends Annotation> {
442
489
.filter (MergedAnnotationPredicates .unique (MergedAnnotation ::getMetaTypes ))
443
490
.collect (MergedAnnotationCollectors .toMultiValueMap (Adapt .CLASS_TO_STRING ));
444
491
MergedAnnotation <A > annotation = annotations .get (annotationType );
445
- this .classLoader = context . getClassLoader () ;
492
+ this .context = context ;
446
493
this .annotationType = annotationType ;
447
494
this .names = extract (attributes , "name" );
448
495
this .annotations = extract (attributes , "annotation" );
@@ -497,7 +544,7 @@ private Set<Class<?>> resolveWhenPossible(Set<String> classNames) {
497
544
Set <Class <?>> resolved = new LinkedHashSet <>(classNames .size ());
498
545
for (String className : classNames ) {
499
546
try {
500
- resolved .add (resolve (className , this .classLoader ));
547
+ resolved .add (resolve (className , this .context . getClassLoader () ));
501
548
}
502
549
catch (ClassNotFoundException | NoClassDefFoundError ex ) {
503
550
// Ignore
@@ -596,31 +643,35 @@ private SearchStrategy getStrategy() {
596
643
return (this .strategy != null ) ? this .strategy : SearchStrategy .ALL ;
597
644
}
598
645
599
- Set <String > getNames () {
646
+ private ConditionContext getContext () {
647
+ return this .context ;
648
+ }
649
+
650
+ private Set <String > getNames () {
600
651
return this .names ;
601
652
}
602
653
603
- Set <String > getTypes () {
654
+ protected Set <String > getTypes () {
604
655
return this .types ;
605
656
}
606
657
607
- Set <String > getAnnotations () {
658
+ private Set <String > getAnnotations () {
608
659
return this .annotations ;
609
660
}
610
661
611
- Set <String > getIgnoredTypes () {
662
+ private Set <String > getIgnoredTypes () {
612
663
return this .ignoredTypes ;
613
664
}
614
665
615
- Set <Class <?>> getParameterizedContainers () {
666
+ private Set <Class <?>> getParameterizedContainers () {
616
667
return this .parameterizedContainers ;
617
668
}
618
669
619
- ConditionMessage .Builder message () {
670
+ private ConditionMessage .Builder message () {
620
671
return ConditionMessage .forCondition (this .annotationType , this );
621
672
}
622
673
623
- ConditionMessage .Builder message (ConditionMessage message ) {
674
+ private ConditionMessage .Builder message (ConditionMessage message ) {
624
675
return message .andCondition (this .annotationType , this );
625
676
}
626
677
0 commit comments