Fix introspection of annotations that use local aliased attributes
Closes gh-28528
This commit is contained in:
@@ -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<Class<?>> 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<Class<?>> types, Class<?> annotationType) {
|
||||
private static void collectAliasedAnnotations(Set<Class<?>> seen, Set<Class<?>> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user