Skip to content

Commit 1ec35e9

Browse files
committed
Support searches for multiple merged annotations with "get" semantics
This commit picks up where a5139f3 left off with added support for "get" search semantics for multiple merged annotations. Specifically, this commit introduces a new getAllMergedAnnotations() method in AnnotatedElementUtils. Issue: SPR-13486
1 parent 3eff478 commit 1ec35e9

File tree

2 files changed

+231
-40
lines changed

2 files changed

+231
-40
lines changed

spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,38 @@ public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement elem
451451
return AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element);
452452
}
453453

454+
/**
455+
* Get <strong>all</strong> annotations of the specified {@code annotationType}
456+
* within the annotation hierarchy <em>above</em> the supplied {@code element};
457+
* and for each annotation found, merge that annotation's attributes with
458+
* <em>matching</em> attributes from annotations in lower levels of the annotation
459+
* hierarchy and synthesize the results back into an annotation of the specified
460+
* {@code annotationType}.
461+
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
462+
* single annotation and within annotation hierarchies.
463+
* <p>This method follows <em>get semantics</em> as described in the
464+
* {@linkplain AnnotatedElementUtils class-level javadoc}.
465+
* @param element the annotated element; never {@code null}
466+
* @param annotationType the annotation type to find; never {@code null}
467+
* @return the set of all merged, synthesized {@code Annotations} found, or an empty
468+
* set if none were found
469+
* @since 4.3
470+
* @see #getMergedAnnotation(AnnotatedElement, Class)
471+
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
472+
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
473+
*/
474+
public static <A extends Annotation> Set<A> getAllMergedAnnotations(AnnotatedElement element,
475+
Class<A> annotationType) {
476+
477+
Assert.notNull(element, "AnnotatedElement must not be null");
478+
Assert.notNull(annotationType, "annotationType must not be null");
479+
480+
MergedAnnotationAttributesProcessor processor =
481+
new MergedAnnotationAttributesProcessor(annotationType, null, false, false, true);
482+
searchWithGetSemantics(element, annotationType, null, processor);
483+
return postProcessAndSynthesizeAggregatedResults(element, annotationType, processor.getAggregatedResults());
484+
}
485+
454486
/**
455487
* Get the annotation attributes of <strong>all</strong> annotations of the specified
456488
* {@code annotationName} in the annotation hierarchy above the supplied
@@ -688,7 +720,7 @@ public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement ele
688720
* within the annotation hierarchy <em>above</em> the supplied {@code element};
689721
* and for each annotation found, merge that annotation's attributes with
690722
* <em>matching</em> attributes from annotations in lower levels of the annotation
691-
* hierarchy and synthesize the result back into an annotation of the specified
723+
* hierarchy and synthesize the results back into an annotation of the specified
692724
* {@code annotationType}.
693725
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
694726
* single annotation and within annotation hierarchies.
@@ -700,6 +732,7 @@ public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement ele
700732
* set if none were found
701733
* @since 4.3
702734
* @see #findMergedAnnotation(AnnotatedElement, Class)
735+
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
703736
*/
704737
public static <A extends Annotation> Set<A> findAllMergedAnnotations(AnnotatedElement element,
705738
Class<A> annotationType) {
@@ -710,21 +743,15 @@ public static <A extends Annotation> Set<A> findAllMergedAnnotations(AnnotatedEl
710743
MergedAnnotationAttributesProcessor processor =
711744
new MergedAnnotationAttributesProcessor(annotationType, null, false, false, true);
712745
searchWithFindSemantics(element, annotationType, annotationType.getName(), processor);
713-
714-
Set<A> annotations = new LinkedHashSet<A>();
715-
for (AnnotationAttributes attributes : processor.getAggregatedResults()) {
716-
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, false, false);
717-
annotations.add(AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element));
718-
}
719-
return annotations;
746+
return postProcessAndSynthesizeAggregatedResults(element, annotationType, processor.getAggregatedResults());
720747
}
721748

722749
/**
723750
* Find all <em>repeatable annotations</em> of the specified {@code annotationType}
724751
* within the annotation hierarchy <em>above</em> the supplied {@code element};
725752
* and for each annotation found, merge that annotation's attributes with
726753
* <em>matching</em> attributes from annotations in lower levels of the annotation
727-
* hierarchy and synthesize the result back into an annotation of the specified
754+
* hierarchy and synthesize the results back into an annotation of the specified
728755
* {@code annotationType}.
729756
* <p>The container type that holds the repeatable annotations will be looked up
730757
* via {@link java.lang.annotation.Repeatable}.
@@ -754,7 +781,7 @@ public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(Anno
754781
* within the annotation hierarchy <em>above</em> the supplied {@code element};
755782
* and for each annotation found, merge that annotation's attributes with
756783
* <em>matching</em> attributes from annotations in lower levels of the annotation
757-
* hierarchy and synthesize the result back into an annotation of the specified
784+
* hierarchy and synthesize the results back into an annotation of the specified
758785
* {@code annotationType}.
759786
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
760787
* single annotation and within annotation hierarchies.
@@ -791,13 +818,7 @@ public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(Anno
791818
MergedAnnotationAttributesProcessor processor =
792819
new MergedAnnotationAttributesProcessor(annotationType, null, false, false, true);
793820
searchWithFindSemantics(element, annotationType, annotationType.getName(), containerType, processor);
794-
795-
Set<A> annotations = new LinkedHashSet<A>();
796-
for (AnnotationAttributes attributes : processor.getAggregatedResults()) {
797-
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, false, false);
798-
annotations.add(AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element));
799-
}
800-
return annotations;
821+
return postProcessAndSynthesizeAggregatedResults(element, annotationType, processor.getAggregatedResults());
801822
}
802823

803824
/**
@@ -906,13 +927,18 @@ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement annota
906927

907928
// Search in annotations
908929
for (Annotation annotation : annotations) {
930+
// Note: we only check for (metaDepth > 0) due to the nuances of getMetaAnnotationTypes().
909931
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) &&
910-
((annotationType != null ? annotation.annotationType() == annotationType :
911-
annotation.annotationType().getName().equals(annotationName)) ||
912-
metaDepth > 0)) {
932+
((annotation.annotationType() == annotationType
933+
|| annotation.annotationType().getName().equals(annotationName)) || metaDepth > 0)) {
913934
T result = processor.process(annotatedElement, annotation, metaDepth);
914935
if (result != null) {
915-
return result;
936+
if (processor.aggregates() && metaDepth == 0) {
937+
processor.getAggregatedResults().add(result);
938+
}
939+
else {
940+
return result;
941+
}
916942
}
917943
}
918944
}
@@ -924,7 +950,12 @@ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement annota
924950
annotationName, processor, visited, metaDepth + 1);
925951
if (result != null) {
926952
processor.postProcess(annotatedElement, annotation, result);
927-
return result;
953+
if (processor.aggregates() && metaDepth == 0) {
954+
processor.getAggregatedResults().add(result);
955+
}
956+
else {
957+
return result;
958+
}
928959
}
929960
}
930961
}
@@ -1234,6 +1265,20 @@ private static void validateRepeatableContainerType(Class<? extends Annotation>
12341265
}
12351266
}
12361267

1268+
/**
1269+
* @since 4.3
1270+
*/
1271+
private static <A extends Annotation> Set<A> postProcessAndSynthesizeAggregatedResults(AnnotatedElement element,
1272+
Class<A> annotationType, List<AnnotationAttributes> aggregatedResults) {
1273+
1274+
Set<A> annotations = new LinkedHashSet<A>();
1275+
for (AnnotationAttributes attributes : aggregatedResults) {
1276+
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, false, false);
1277+
annotations.add(AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element));
1278+
}
1279+
return annotations;
1280+
}
1281+
12371282

12381283
/**
12391284
* Callback interface that is used to process annotations during a search.
@@ -1305,7 +1350,6 @@ private interface Processor<T> {
13051350
* Determine if this processor aggregates the results returned by {@link #process}.
13061351
* <p>If this method returns {@code true}, then {@link #getAggregatedResults()}
13071352
* must return a non-null value.
1308-
* <p>WARNING: aggregation is currently only supported for <em>find semantics</em>.
13091353
* @return {@code true} if this processor supports aggregated results
13101354
* @see #getAggregatedResults
13111355
* @since 4.3
@@ -1319,7 +1363,6 @@ private interface Processor<T> {
13191363
* responsible for asking this processor if it {@link #aggregates} results
13201364
* and then adding the post-processed results to the list returned by this
13211365
* method.
1322-
* <p>WARNING: aggregation is currently only supported for <em>find semantics</em>.
13231366
* @return the list of results aggregated by this processor; never
13241367
* {@code null} unless {@link #aggregates} returns {@code false}
13251368
* @see #aggregates

0 commit comments

Comments
 (0)