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 6d18d41dd0..3a0e323994 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 @@ -18,6 +18,7 @@ package org.springframework.aot.hint.support; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import java.util.function.Consumer; @@ -55,24 +56,31 @@ public abstract class RuntimeHintsUtils { * @see SynthesizedAnnotation */ public static void registerAnnotation(RuntimeHints hints, Class annotationType) { + hints.reflection().registerType(annotationType, ANNOTATION_HINT); Set> allAnnotations = new LinkedHashSet<>(); - allAnnotations.add(annotationType); - collectAliasedAnnotations(allAnnotations, annotationType); + collectAliasedAnnotations(new HashSet<>(), allAnnotations, annotationType); allAnnotations.forEach(annotation -> hints.reflection().registerType(annotation, ANNOTATION_HINT)); - if (allAnnotations.size() > 1) { + if (allAnnotations.size() > 0) { hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class); } } - private static void collectAliasedAnnotations(Set> types, Class annotationType) { + private static void collectAliasedAnnotations(Set> seen, Set> types, Class annotationType) { + if (seen.contains(annotationType)) { + return; + } + seen.add(annotationType); for (Method method : annotationType.getDeclaredMethods()) { MergedAnnotations methodAnnotations = MergedAnnotations.from(method); if (methodAnnotations.isPresent(AliasFor.class)) { - Class aliasedAnnotation = methodAnnotations.get(AliasFor.class).getClass("annotation"); - boolean process = (aliasedAnnotation != Annotation.class && !types.contains(aliasedAnnotation)); - if (process) { - types.add(aliasedAnnotation); - collectAliasedAnnotations(types, aliasedAnnotation); + Class annotationAttribute = methodAnnotations.get(AliasFor.class).getClass("annotation"); + Class targetAnnotation = (annotationAttribute != Annotation.class + ? annotationAttribute : annotationType); + if (!types.contains(targetAnnotation)) { + types.add(targetAnnotation); + if (!targetAnnotation.equals(annotationType)) { + collectAliasedAnnotations(seen, types, targetAnnotation); + } } } } diff --git a/spring-core/src/test/java/org/springframework/aot/hint/support/RuntimeHintsUtilsTests.java b/spring-core/src/test/java/org/springframework/aot/hint/support/RuntimeHintsUtilsTests.java index df7114aae4..3533bd7ca7 100644 --- a/spring-core/src/test/java/org/springframework/aot/hint/support/RuntimeHintsUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/aot/hint/support/RuntimeHintsUtilsTests.java @@ -53,6 +53,15 @@ class RuntimeHintsUtilsTests { assertThat(this.hints.proxies().jdkProxies()).isEmpty(); } + @Test + void registerAnnotationTypeWithLocalUseOfAliasForRegistersProxy() { + RuntimeHintsUtils.registerAnnotation(this.hints, LocalMapping.class); + assertThat(this.hints.reflection().typeHints()).singleElement() + .satisfies(annotationHint(LocalMapping.class)); + assertThat(this.hints.proxies().jdkProxies()).singleElement() + .satisfies(annotationProxy(LocalMapping.class)); + } + @Test void registerAnnotationTypeProxyRegistersJdkProxy() { RuntimeHintsUtils.registerAnnotation(this.hints, RetryInvoker.class); @@ -108,6 +117,19 @@ class RuntimeHintsUtilsTests { } + @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) + @Retention(RetentionPolicy.RUNTIME) + @Documented + @interface LocalMapping { + + @AliasFor("retries") + int value() default 0; + + @AliasFor("value") + int retries() default 0; + + } + @Target({ ElementType.TYPE, ElementType.ANNOTATION_TYPE }) @Retention(RetentionPolicy.RUNTIME)