Stop implementing SynthesizedAnnotation in annotation proxies

SynthesizedAnnotation was originally introduced as a convenience for
easily detecting if an annotation had been synthesized by Spring via a
simple `if (myAnnotation instanceof SynthesizedAnnotation)` check.

However, the introduction of SynthesizedAnnotation in the JDK dynamic
proxy for a synthesized annotation results in a separate proxy class
for each annotation synthesized by Spring, and this causes issues with
GraalVM native images since users and framework developers must always
ensure that the additional proxy classes are registered.

This commit completely removes the use of SynthesizedAnnotation in
synthesized annotation proxies. This change allows the proxy class for
an annotation to be reused for a synthesized annotation of the same
annotation type.

Consequently:

- Extra proxy classes are not generated on the JVM or in a native image.
- Extra proxy classes are not required to be registered for a native image.

Closes gh-29041
This commit is contained in:
Sam Brannen
2022-09-02 11:00:40 +02:00
parent 7214b1e03c
commit 0ec03a8dd6
5 changed files with 32 additions and 20 deletions

View File

@@ -1511,6 +1511,26 @@ class MergedAnnotationsTests {
assertThat(MergedAnnotation.from(component).isSynthesizable()).isFalse();
}
/**
* @since 6.0
*/
@Test
void synthesizedAnnotationShouldReuseJdkProxyClass() throws Exception {
Method method = WebController.class.getMethod("handleMappedWithValueAttribute");
RequestMapping jdkRequestMapping = method.getAnnotation(RequestMapping.class);
assertThat(jdkRequestMapping).isNotNull();
assertThat(jdkRequestMapping.value()).containsExactly("/test");
assertThat(jdkRequestMapping.path()).containsExactly("");
RequestMapping synthesizedRequestMapping = MergedAnnotation.from(jdkRequestMapping).synthesize();
assertSynthesized(synthesizedRequestMapping);
assertThat(synthesizedRequestMapping.value()).containsExactly("/test");
assertThat(synthesizedRequestMapping.path()).containsExactly("/test");
assertThat(jdkRequestMapping.getClass()).isSameAs(synthesizedRequestMapping.getClass());
}
@Test
void synthesizeAlreadySynthesized() throws Exception {
Method method = WebController.class.getMethod("handleMappedWithValueAttribute");
@@ -1585,7 +1605,6 @@ class MergedAnnotationsTests {
mergedAnnotations.get(EnableGlobalAuthentication.class);
assertThat(enableGlobalAuthenticationMergedAnnotation.isSynthesizable()).isFalse();
EnableGlobalAuthentication enableGlobalAuthentication = enableGlobalAuthenticationMergedAnnotation.synthesize();
assertThat(enableGlobalAuthentication).isNotInstanceOf(SynthesizedAnnotation.class);
assertNotSynthesized(enableGlobalAuthentication);
}