Skip to content

Commit

Permalink
Support nesting in AnnotatedElementUtils.getMergedRepeatableAnnotatio…
Browse files Browse the repository at this point in the history
…ns()

This commit is a follow up to 828f74f
and applies to same fix for getMergedRepeatableAnnotations().

See the previous commit for details.

Closes gh-20279
  • Loading branch information
sbrannen committed Oct 11, 2022
1 parent 828f74f commit 9876701
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
Expand Up @@ -766,7 +766,23 @@ private static MergedAnnotations getAnnotations(AnnotatedElement element) {
private static MergedAnnotations getRepeatableAnnotations(AnnotatedElement element,
@Nullable Class<? extends Annotation> containerType, Class<? extends Annotation> annotationType) {

RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType);
RepeatableContainers repeatableContainers;
if (containerType == null) {
// Invoke RepeatableContainers.of() in order to adhere to the contract of
// getMergedRepeatableAnnotations() which states that an IllegalArgumentException
// will be thrown if the the container cannot be resolved.
//
// In any case, we use standardRepeatables() in order to support repeatable
// annotations on other types of repeatable annotations (i.e., nested repeatable
// annotation types).
//
// See https://github.com/spring-projects/spring-framework/issues/20279
RepeatableContainers.of(annotationType, null);
repeatableContainers = RepeatableContainers.standardRepeatables();
}
else {
repeatableContainers = RepeatableContainers.of(annotationType, containerType);
}
return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, repeatableContainers);
}

Expand Down
Expand Up @@ -64,6 +64,20 @@ void findMergedRepeatableAnnotations_AnnotatedElementUtils() {
assertThat(annotations).extracting(A::value).containsExactly(5);
}

@Test
void getMergedRepeatableAnnotationsWithStandardRepeatables_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class);
// Merged, so we expect to find @A once with its value coming from @B(5).
assertThat(annotations).extracting(A::value).containsExactly(5);
}

@Test
void getMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class, A.Container.class);
// Merged, so we expect to find @A once with its value coming from @B(5).
assertThat(annotations).extracting(A::value).containsExactly(5);
}

@Test
@SuppressWarnings("deprecation")
void getRepeatableAnnotations_AnnotationUtils() {
Expand Down Expand Up @@ -107,7 +121,6 @@ void streamRepeatableAnnotationsWithExplicitRepeatables_MergedAnnotationsApi() {
void findMergedRepeatableAnnotationsWithStandardRepeatables_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.findMergedRepeatableAnnotations(method, A.class);
// Merged, so we expect to find @A twice with values coming from @B(5) and @B(10).
// However, findMergedRepeatableAnnotations() currently finds ZERO annotations.
assertThat(annotations).extracting(A::value).containsExactly(5, 10);
}

Expand All @@ -126,6 +139,28 @@ void findMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils(
assertThat(annotations).isEmpty();
}

@Test
void getMergedRepeatableAnnotationsWithStandardRepeatables_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class);
// Merged, so we expect to find @A twice with values coming from @B(5) and @B(10).
assertThat(annotations).extracting(A::value).containsExactly(5, 10);
}

@Test
void getMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils() {
Set<A> annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class, A.Container.class);
// When getMergedRepeatableAnnotations(...) is invoked with an explicit container
// type, it uses RepeatableContainers.of(...) which limits the repeatable annotation
// support to a single container type.
//
// In this test case, we are therefore limiting the support to @A.Container, which
// means that @B.Container is unsupported and effectively ignored as a repeatable
// container type.
//
// Long story, short: the search doesn't find anything.
assertThat(annotations).isEmpty();
}

@Test
@SuppressWarnings("deprecation")
void getRepeatableAnnotations_AnnotationUtils() {
Expand Down

0 comments on commit 9876701

Please sign in to comment.