mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-10-07 15:39:29 +00:00
Fix container detection in RepeatableContainers.standardRepeatables()
StandardRepeatableContainers.computeRepeatedAnnotationsMethod() previously treated any annotation as a container annotation if it merely declared a `value` attribute returning an array of a @Repeatable annotated type, without verifying that the repeatable annotation actually references the candidate container via @Repeatable.value(). Consequently, an unrelated annotation that happened to have the same shape as the official container (e.g. a "fake" container with a `value` attribute returning the same repeatable type) was incorrectly recognized as a container. This commit aligns the detection logic with the Java language semantics by additionally asserting that the container type declared in @Repeatable.value() is identical to the candidate annotation type. Closes gh-37326 Signed-off-by: Chengang Guan <guanchengang@qq.com>
This commit is contained in:
+5
-3
@@ -274,9 +274,11 @@ public abstract class RepeatableContainers {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (returnType.isArray()) {
|
||||
Class<?> componentType = returnType.componentType();
|
||||
if (Annotation.class.isAssignableFrom(componentType) &&
|
||||
componentType.isAnnotationPresent(Repeatable.class)) {
|
||||
return method;
|
||||
if (Annotation.class.isAssignableFrom(componentType)) {
|
||||
Repeatable repeatable = componentType.getAnnotation(Repeatable.class);
|
||||
if (repeatable != null && repeatable.value() == annotationType) {
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -37,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Sam Brannen
|
||||
* @author Chengang Guan
|
||||
*/
|
||||
class RepeatableContainersTests {
|
||||
|
||||
@@ -79,6 +80,13 @@ class RepeatableContainersTests {
|
||||
assertThat(values).containsExactly("a", "b");
|
||||
}
|
||||
|
||||
@Test
|
||||
void standardRepeatablesWhenContainerNotReferencedByRepeatableReturnsNull() {
|
||||
Object[] values = findRepeatedAnnotationValues(RepeatableContainers.standardRepeatables(),
|
||||
FakeRepeatablesTestCase.class, FakeStandardContainer.class);
|
||||
assertThat(values).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -211,6 +219,12 @@ class RepeatableContainersTests {
|
||||
StandardRepeatable[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface FakeStandardContainer {
|
||||
|
||||
StandardRepeatable[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(StandardContainer.class)
|
||||
@interface StandardRepeatable {
|
||||
@@ -263,4 +277,8 @@ class RepeatableContainersTests {
|
||||
static class ExplicitRepeatablesTestCase {
|
||||
}
|
||||
|
||||
@FakeStandardContainer({ @StandardRepeatable("a"), @StandardRepeatable("b") })
|
||||
static class FakeRepeatablesTestCase {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user