Fix introspection of annotations that use local aliased attributes

Closes gh-28528
This commit is contained in:
Stephane Nicoll
2022-05-26 15:50:41 +02:00
parent 9e1d0057bc
commit 86a85f558c
2 changed files with 39 additions and 9 deletions

View File

@@ -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);
}
}
}
}

View File

@@ -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)