Skip to content

Commit cb7f997

Browse files
committed
Defensively copy array returned from forAnnotations
Update the proxy used in `AnnotatedElementUtils.forAnnotations` so that it returns a cloned array for calls to `getDeclaredAnnotations` or `getAnnotations`. This matches the behavior of standard JDK `AnnotatedElement` implementations. Closes gh-22655
1 parent 78fd882 commit cb7f997

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -864,12 +864,12 @@ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
864864

865865
@Override
866866
public Annotation[] getAnnotations() {
867-
return this.annotations;
867+
return this.annotations.clone();
868868
}
869869

870870
@Override
871871
public Annotation[] getDeclaredAnnotations() {
872-
return this.annotations;
872+
return this.annotations.clone();
873873
}
874874

875875
};

spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
import java.lang.annotation.RetentionPolicy;
2424
import java.lang.annotation.Target;
2525
import java.lang.reflect.AnnotatedElement;
26-
import java.lang.reflect.Constructor;
2726
import java.lang.reflect.Method;
28-
import java.util.Date;
2927
import java.util.List;
3028
import java.util.Set;
3129
import javax.annotation.Resource;
@@ -43,6 +41,7 @@
4341

4442
import static java.util.Arrays.*;
4543
import static java.util.stream.Collectors.*;
44+
import static org.assertj.core.api.Assertions.assertThat;
4645
import static org.hamcrest.Matchers.*;
4746
import static org.junit.Assert.*;
4847
import static org.springframework.core.annotation.AnnotatedElementUtils.*;
@@ -736,6 +735,15 @@ public void findMethodAnnotationFromGenericSuperclass() throws Exception {
736735
assertNotNull(order);
737736
}
738737

738+
@Test // gh-22655
739+
public void forAnnotationsCreatesCopyOfArrayOnEachCall() {
740+
AnnotatedElement element = AnnotatedElementUtils.forAnnotations(ForAnnotationsClass.class.getDeclaredAnnotations());
741+
// Trigger the NPE as originally reported in the bug
742+
AnnotationsScanner.getDeclaredAnnotations(element, false);
743+
AnnotationsScanner.getDeclaredAnnotations(element, false);
744+
// Also specifically test we get different instances
745+
assertThat(element.getDeclaredAnnotations()).isNotSameAs(element.getDeclaredAnnotations());
746+
}
739747

740748
// -------------------------------------------------------------------------
741749

@@ -1301,4 +1309,10 @@ public void doIt() {
13011309
}
13021310
}
13031311

1312+
@Deprecated
1313+
@ComponentScan
1314+
class ForAnnotationsClass {
1315+
1316+
}
1317+
13041318
}

0 commit comments

Comments
 (0)