Browse Source

Register annotation based on its type

This commit improves registerAnnotation to use the annotation type
rather than a `MergedAnnotation` attribute.

See gh-28497
pull/28538/head
Stephane Nicoll 4 years ago
parent
commit
059b66bf26
  1. 8
      spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java
  2. 4
      spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java
  3. 43
      spring-core/src/main/java/org/springframework/aot/hint/support/RuntimeHintsUtils.java
  4. 9
      spring-core/src/main/java/org/springframework/core/annotation/CoreAnnotationsRuntimeHintsRegistrar.java
  5. 29
      spring-core/src/test/java/org/springframework/aot/hint/support/RuntimeHintsUtilsTests.java
  6. 4
      spring-core/src/test/java/org/springframework/core/annotation/CoreAnnotationsRuntimeHintsRegistrarTests.java

8
spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java

@ -27,10 +27,8 @@ import java.util.Set; @@ -27,10 +27,8 @@ import java.util.Set;
import java.util.function.Consumer;
import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeHint.Builder;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.aot.hint.annotation.ReflectiveProcessor;
import org.springframework.aot.hint.support.RuntimeHintsUtils;
@ -118,8 +116,6 @@ class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistratio @@ -118,8 +116,6 @@ class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistratio
private static class ReflectiveProcessorBeanRegistrationAotContribution implements BeanRegistrationAotContribution {
private static final Consumer<Builder> ANNOTATION_CUSTOMIZATIONS = hint -> hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS);
private final Iterable<Entry> entries;
public ReflectiveProcessorBeanRegistrationAotContribution(Iterable<Entry> entries) {
@ -129,7 +125,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistratio @@ -129,7 +125,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistratio
@Override
public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) {
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
runtimeHints.reflection().registerType(Reflective.class, ANNOTATION_CUSTOMIZATIONS);
RuntimeHintsUtils.registerAnnotation(runtimeHints, Reflective.class);
this.entries.forEach(entry -> {
AnnotatedElement element = entry.element();
entry.processor().registerReflectionHints(runtimeHints.reflection(), element);
@ -140,7 +136,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistratio @@ -140,7 +136,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistratio
private void registerAnnotationIfNecessary(RuntimeHints hints, AnnotatedElement element) {
MergedAnnotation<Reflective> reflectiveAnnotation = MergedAnnotations.from(element).get(Reflective.class);
if (reflectiveAnnotation.getDistance() > 0) {
RuntimeHintsUtils.registerAnnotation(hints, reflectiveAnnotation.getRoot());
RuntimeHintsUtils.registerAnnotation(hints, reflectiveAnnotation.getRoot().getType());
}
}

4
spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java

@ -97,7 +97,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests { @@ -97,7 +97,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests {
process(SampleMethodMetaAnnotatedBean.class);
RuntimeHints runtimeHints = this.generationContext.getRuntimeHints();
assertThat(runtimeHints.reflection().getTypeHint(SampleInvoker.class)).satisfies(typeHint ->
assertThat(typeHint.getMemberCategories()).containsOnly(MemberCategory.INVOKE_PUBLIC_METHODS));
assertThat(typeHint.getMemberCategories()).containsOnly(MemberCategory.INVOKE_DECLARED_METHODS));
assertThat(runtimeHints.proxies().jdkProxies()).isEmpty();
}
@ -106,7 +106,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests { @@ -106,7 +106,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests {
process(SampleMethodMetaAnnotatedBeanWithAlias.class);
RuntimeHints runtimeHints = this.generationContext.getRuntimeHints();
assertThat(runtimeHints.reflection().getTypeHint(RetryInvoker.class)).satisfies(typeHint ->
assertThat(typeHint.getMemberCategories()).containsOnly(MemberCategory.INVOKE_PUBLIC_METHODS));
assertThat(typeHint.getMemberCategories()).containsOnly(MemberCategory.INVOKE_DECLARED_METHODS));
assertThat(runtimeHints.proxies().jdkProxies()).anySatisfy(jdkProxyHint ->
assertThat(jdkProxyHint.getProxiedInterfaces()).containsExactly(
TypeReference.of(RetryInvoker.class), TypeReference.of(SynthesizedAnnotation.class)));

43
spring-core/src/main/java/org/springframework/aot/hint/support/RuntimeHintsUtils.java

@ -16,13 +16,18 @@ @@ -16,13 +16,18 @@
package org.springframework.aot.hint.support;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.Consumer;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeHint;
import org.springframework.aot.hint.TypeHint.Builder;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.SynthesizedAnnotation;
/**
@ -38,24 +43,38 @@ public abstract class RuntimeHintsUtils { @@ -38,24 +43,38 @@ public abstract class RuntimeHintsUtils {
* that its attributes are visible.
*/
public static final Consumer<Builder> ANNOTATION_HINT = hint ->
hint.withMembers(MemberCategory.INVOKE_PUBLIC_METHODS);
hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS);
/**
* Register the necessary hints so that the specified annotation is visible
* at runtime.
* at runtime. If an annotation attributes aliases an attribute of another
* annotation, it is registered as well and a JDK proxy hints is defined
* so that the synthesized annotation can be resolved.
* @param hints the {@link RuntimeHints} instance ot use
* @param annotation the annotation
* @param annotationType the annotation type
* @see SynthesizedAnnotation
*/
public static void registerAnnotation(RuntimeHints hints, MergedAnnotation<?> annotation) {
hints.reflection().registerType(annotation.getType(), ANNOTATION_HINT);
MergedAnnotation<?> parentSource = annotation.getMetaSource();
while (parentSource != null) {
hints.reflection().registerType(parentSource.getType(), ANNOTATION_HINT);
parentSource = parentSource.getMetaSource();
public static void registerAnnotation(RuntimeHints hints, Class<?> annotationType) {
Set<Class<?>> allAnnotations = new LinkedHashSet<>();
allAnnotations.add(annotationType);
collectAliasedAnnotations(allAnnotations, annotationType);
allAnnotations.forEach(annotation -> hints.reflection().registerType(annotation, ANNOTATION_HINT));
if (allAnnotations.size() > 1) {
hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class);
}
if (annotation.synthesize() instanceof SynthesizedAnnotation) {
hints.proxies().registerJdkProxy(annotation.getType(), SynthesizedAnnotation.class);
}
private static void collectAliasedAnnotations(Set<Class<?>> types, Class<?> 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);
}
}
}
}

9
spring-core/src/main/java/org/springframework/core/annotation/CoreAnnotationsRuntimeHintsRegistrar.java

@ -16,9 +16,12 @@ @@ -16,9 +16,12 @@
package org.springframework.core.annotation;
import java.util.stream.Stream;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.support.RuntimeHintsUtils;
import org.springframework.lang.Nullable;
/**
* {@link RuntimeHintsRegistrar} for core annotations.
@ -29,9 +32,9 @@ import org.springframework.aot.hint.support.RuntimeHintsUtils; @@ -29,9 +32,9 @@ import org.springframework.aot.hint.support.RuntimeHintsUtils;
class CoreAnnotationsRuntimeHintsRegistrar implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(AliasFor.class, RuntimeHintsUtils.ANNOTATION_HINT)
.registerType(Order.class, RuntimeHintsUtils.ANNOTATION_HINT);
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
Stream.of(AliasFor.class, Order.class).forEach(annotationType ->
RuntimeHintsUtils.registerAnnotation(hints, annotationType));
}
}

29
spring-core/src/test/java/org/springframework/aot/hint/support/RuntimeHintsUtilsTests.java

@ -32,7 +32,6 @@ import org.springframework.aot.hint.RuntimeHints; @@ -32,7 +32,6 @@ import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeHint;
import org.springframework.aot.hint.TypeReference;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.SynthesizedAnnotation;
import static org.assertj.core.api.Assertions.assertThat;
@ -47,36 +46,34 @@ class RuntimeHintsUtilsTests { @@ -47,36 +46,34 @@ class RuntimeHintsUtilsTests {
private final RuntimeHints hints = new RuntimeHints();
@Test
void registerAnnotation() {
RuntimeHintsUtils.registerAnnotation(this.hints, MergedAnnotations
.from(SampleInvokerClass.class).get(SampleInvoker.class));
void registerAnnotationType() {
RuntimeHintsUtils.registerAnnotation(this.hints, SampleInvoker.class);
assertThat(this.hints.reflection().typeHints()).singleElement()
.satisfies(annotationHint(SampleInvoker.class));
assertThat(this.hints.proxies().jdkProxies()).isEmpty();
}
@Test
void registerAnnotationProxyRegistersJdkProxy() {
RuntimeHintsUtils.registerAnnotation(this.hints, MergedAnnotations
.from(RetryInvokerClass.class).get(RetryInvoker.class));
assertThat(this.hints.reflection().typeHints()).singleElement()
.satisfies(annotationHint(RetryInvoker.class));
void registerAnnotationTypeProxyRegistersJdkProxy() {
RuntimeHintsUtils.registerAnnotation(this.hints, RetryInvoker.class);
assertThat(this.hints.reflection().typeHints())
.anySatisfy(annotationHint(RetryInvoker.class))
.anySatisfy(annotationHint(SampleInvoker.class));
assertThat(this.hints.proxies().jdkProxies()).singleElement()
.satisfies(annotationProxy(RetryInvoker.class));
}
@Test
void registerAnnotationWhereUsedAsAMetaAnnotationRegistersHierarchy() {
RuntimeHintsUtils.registerAnnotation(this.hints, MergedAnnotations
.from(RetryWithEnabledFlagInvokerClass.class).get(SampleInvoker.class));
void registerAnnotationTypeWhereUsedAsAMetaAnnotationRegistersHierarchy() {
RuntimeHintsUtils.registerAnnotation(this.hints, RetryWithEnabledFlagInvoker.class);
ReflectionHints reflection = this.hints.reflection();
assertThat(reflection.typeHints())
.anySatisfy(annotationHint(SampleInvoker.class))
.anySatisfy(annotationHint(RetryInvoker.class))
.anySatisfy(annotationHint(RetryWithEnabledFlagInvoker.class))
.anySatisfy(annotationHint(RetryInvoker.class))
.anySatisfy(annotationHint(SampleInvoker.class))
.hasSize(3);
assertThat(this.hints.proxies().jdkProxies()).singleElement()
.satisfies(annotationProxy(SampleInvoker.class));
.satisfies(annotationProxy(RetryWithEnabledFlagInvoker.class));
}
private Consumer<TypeHint> annotationHint(Class<?> type) {
@ -85,7 +82,7 @@ class RuntimeHintsUtilsTests { @@ -85,7 +82,7 @@ class RuntimeHintsUtilsTests {
assertThat(typeHint.constructors()).isEmpty();
assertThat(typeHint.fields()).isEmpty();
assertThat(typeHint.methods()).isEmpty();
assertThat(typeHint.getMemberCategories()).containsOnly(MemberCategory.INVOKE_PUBLIC_METHODS);
assertThat(typeHint.getMemberCategories()).containsOnly(MemberCategory.INVOKE_DECLARED_METHODS);
};
}

4
spring-core/src/test/java/org/springframework/core/annotation/CoreAnnotationsRuntimeHintsRegistrarTests.java

@ -49,14 +49,14 @@ class CoreAnnotationsRuntimeHintsRegistrarTests { @@ -49,14 +49,14 @@ class CoreAnnotationsRuntimeHintsRegistrarTests {
void aliasForHasHints() {
assertThat(this.hints.reflection().getTypeHint(TypeReference.of(AliasFor.class)))
.satisfies(hint -> assertThat(hint.getMemberCategories())
.containsExactly(MemberCategory.INVOKE_PUBLIC_METHODS));
.containsExactly(MemberCategory.INVOKE_DECLARED_METHODS));
}
@Test
void orderAnnotationHasHints() {
assertThat(this.hints.reflection().getTypeHint(TypeReference.of(Order.class)))
.satisfies(hint -> assertThat(hint.getMemberCategories())
.containsExactly(MemberCategory.INVOKE_PUBLIC_METHODS));
.containsExactly(MemberCategory.INVOKE_DECLARED_METHODS));
}
}

Loading…
Cancel
Save