diff --git a/spring-core/src/main/java/org/springframework/aot/hint/support/RuntimeHintsUtils.java b/spring-core/src/main/java/org/springframework/aot/hint/support/RuntimeHintsUtils.java
index da88f675ba..6f687889a4 100644
--- a/spring-core/src/main/java/org/springframework/aot/hint/support/RuntimeHintsUtils.java
+++ b/spring-core/src/main/java/org/springframework/aot/hint/support/RuntimeHintsUtils.java
@@ -49,7 +49,6 @@ public abstract class RuntimeHintsUtils {
* at runtime.
* @param hints the {@link RuntimeHints} instance to use
* @param annotationType the annotation type
- * @see SynthesizedAnnotation
* @deprecated as annotation attributes are visible without additional hints
*/
@Deprecated
@@ -70,7 +69,6 @@ public abstract class RuntimeHintsUtils {
* that determines if the hints are required.
* @param hints the {@link RuntimeHints} instance to use
* @param annotationType the annotation type
- * @see SynthesizedAnnotation
*/
public static void registerSynthesizedAnnotation(RuntimeHints hints, Class> annotationType) {
hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class);
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
index f42873522f..53add8a193 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
@@ -22,6 +22,7 @@ import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -1288,7 +1289,15 @@ public abstract class AnnotationUtils {
* @since 5.3.23
*/
public static boolean isSynthesizedAnnotation(@Nullable Annotation annotation) {
- return (annotation instanceof SynthesizedAnnotation);
+ try {
+ return ((annotation != null) && Proxy.isProxyClass(annotation.getClass()) &&
+ (Proxy.getInvocationHandler(annotation) instanceof SynthesizedMergedAnnotationInvocationHandler));
+ }
+ catch (SecurityException ex) {
+ // Security settings disallow reflective access to the InvocationHandler:
+ // assume the annotation has not been synthesized by Spring.
+ return false;
+ }
}
/**
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedMergedAnnotationInvocationHandler.java b/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedMergedAnnotationInvocationHandler.java
index 992b1a07fa..c8eaf22e41 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedMergedAnnotationInvocationHandler.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/SynthesizedMergedAnnotationInvocationHandler.java
@@ -299,9 +299,8 @@ final class SynthesizedMergedAnnotationInvocationHandler i
@SuppressWarnings("unchecked")
static A createProxy(MergedAnnotation annotation, Class type) {
ClassLoader classLoader = type.getClassLoader();
+ Class>[] interfaces = new Class>[] {type};
InvocationHandler handler = new SynthesizedMergedAnnotationInvocationHandler<>(annotation, type);
- Class>[] interfaces = isVisible(classLoader, SynthesizedAnnotation.class) ?
- new Class>[] {type, SynthesizedAnnotation.class} : new Class>[] {type};
return (A) Proxy.newProxyInstance(classLoader, interfaces, handler);
}
@@ -310,17 +309,4 @@ final class SynthesizedMergedAnnotationInvocationHandler i
return (canonicalName != null ? canonicalName : clazz.getName());
}
-
- private static boolean isVisible(ClassLoader classLoader, Class> interfaceClass) {
- if (classLoader == interfaceClass.getClassLoader()) {
- return true;
- }
- try {
- return Class.forName(interfaceClass.getName(), false, classLoader) == interfaceClass;
- }
- catch (ClassNotFoundException ex) {
- return false;
- }
- }
-
}
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java
index 1fcbb18883..c2ae3a5dc7 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java
@@ -363,7 +363,7 @@ final class TypeMappedAnnotation extends AbstractMergedAnn
* @since 5.3.22
*/
private boolean isSynthesizable(Annotation annotation) {
- if (annotation instanceof SynthesizedAnnotation) {
+ if (AnnotationUtils.isSynthesizedAnnotation(annotation)) {
return false;
}
return isSynthesizable();
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java
index 1f9ee30680..d97e10050b 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java
@@ -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);
}