Scan annotations on method in interface hierarchy only once

Prior to this commit, the AnnotationsScanner used in the
MergedAnnotations infrastructure found duplicate annotations on methods
within multi-level interface hierarchies.

This commit addresses this issue by scanning methods at a given level
in the interface hierarchy using ReflectionUtils#getDeclaredMethods
instead of Class#getMethods, since the latter includes public methods
declared in super-interfaces which will anyway be scanned when
processing super-interfaces recursively.

Closes gh-31803
This commit is contained in:
Sam Brannen
2023-12-12 18:28:48 +01:00
parent 952223dcf9
commit 75da9c3c47
3 changed files with 47 additions and 3 deletions

View File

@@ -357,6 +357,15 @@ class AnnotationsScannerTests {
Method source = methodFrom(WithSingleInterface.class);
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly(
"0:TestAnnotation1", "1:TestAnnotation2", "1:TestInheritedAnnotation2");
source = methodFrom(Hello1Impl.class);
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("1:TestAnnotation1");
}
@Test // gh-31803
void typeHierarchyStrategyOnMethodWhenHasInterfaceHierarchyScansInterfacesOnlyOnce() {
Method source = methodFrom(Hello2Impl.class);
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("1:TestAnnotation1");
}
@Test
@@ -691,6 +700,30 @@ class AnnotationsScannerTests {
}
}
interface Hello1 {
@TestAnnotation1
void method();
}
interface Hello2 extends Hello1 {
}
static class Hello1Impl implements Hello1 {
@Override
public void method() {
}
}
static class Hello2Impl implements Hello2 {
@Override
public void method() {
}
}
@TestAnnotation2
@TestInheritedAnnotation2
static class HierarchySuperclass extends HierarchySuperSuperclass {

View File

@@ -40,6 +40,8 @@ import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationsScannerTests.Hello2Impl;
import org.springframework.core.annotation.AnnotationsScannerTests.TestAnnotation1;
import org.springframework.core.annotation.MergedAnnotation.Adapt;
import org.springframework.core.annotation.MergedAnnotations.Search;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
@@ -686,6 +688,16 @@ class MergedAnnotationsTests {
assertThat(annotation.getAggregateIndex()).isEqualTo(1);
}
@Test // gh-31803
void streamWithTypeHierarchyInheritedFromSuperInterfaceMethod() throws Exception {
Method method = Hello2Impl.class.getMethod("method");
long count = MergedAnnotations.search(SearchStrategy.TYPE_HIERARCHY)
.from(method)
.stream(TestAnnotation1.class)
.count();
assertThat(count).isEqualTo(1);
}
@Test
void getWithTypeHierarchyInheritedFromAbstractMethod() throws NoSuchMethodException {
Method method = ConcreteClassWithInheritedAnnotation.class.getMethod("handle");