|
|
|
|
@@ -16,19 +16,9 @@
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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.aot.hint.annotation.Reflective;
|
|
|
|
|
import org.springframework.core.annotation.AliasFor;
|
|
|
|
|
import org.springframework.core.annotation.MergedAnnotation;
|
|
|
|
|
import org.springframework.core.annotation.SynthesizedAnnotation;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -40,72 +30,48 @@ import org.springframework.core.annotation.SynthesizedAnnotation;
|
|
|
|
|
*/
|
|
|
|
|
public abstract class RuntimeHintsUtils {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A {@link TypeHint} customizer suitable for an annotation. Make sure
|
|
|
|
|
* that its attributes are visible.
|
|
|
|
|
*/
|
|
|
|
|
public static final Consumer<Builder> ANNOTATION_HINT = hint ->
|
|
|
|
|
hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Register the necessary hints so that the specified annotation is visible
|
|
|
|
|
* at runtime.
|
|
|
|
|
* <p>If an annotation attribute aliases an attribute of another annotation,
|
|
|
|
|
* the other annotation is registered as well and a JDK proxy hint is defined
|
|
|
|
|
* so that the synthesized annotation can be resolved.
|
|
|
|
|
* @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
|
|
|
|
|
public static void registerAnnotation(RuntimeHints hints, Class<?> annotationType) {
|
|
|
|
|
registerSynthesizedAnnotation(hints, annotationType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Register the necessary hints so that the specified annotation can be
|
|
|
|
|
* synthesized at runtime if necessary. Such hints are usually required
|
|
|
|
|
* if any of the following apply:
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li>Use {@link AliasFor} for local aliases</li>
|
|
|
|
|
* <li>Has a meta-annotation that uses {@link AliasFor} for attribute overrides</li>
|
|
|
|
|
* <li>Has nested annotations or arrays of annotations that are synthesizable</li>
|
|
|
|
|
* </ul>
|
|
|
|
|
* Consider using {@link #registerAnnotationIfNecessary(RuntimeHints, MergedAnnotation)}
|
|
|
|
|
* 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 registerAnnotation(RuntimeHints hints, Class<?> annotationType) {
|
|
|
|
|
registerAnnotation(hints, annotationType, false);
|
|
|
|
|
public static void registerSynthesizedAnnotation(RuntimeHints hints, Class<?> annotationType) {
|
|
|
|
|
hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Register the necessary hints so that the specified <em>composable</em>
|
|
|
|
|
* annotation is visible at runtime. Use this method rather than the regular
|
|
|
|
|
* {@link #registerAnnotation(RuntimeHints, Class)} when the specified
|
|
|
|
|
* annotation is meta-annotated, but the meta-annotated annotations do not
|
|
|
|
|
* need to be visible.
|
|
|
|
|
* Determine if the specified annotation can be synthesized at runtime, and
|
|
|
|
|
* register the necessary hints accordingly.
|
|
|
|
|
* @param hints the {@link RuntimeHints} instance to use
|
|
|
|
|
* @param annotationType the composable annotation type
|
|
|
|
|
* @see #registerAnnotation(RuntimeHints, Class)
|
|
|
|
|
* @param annotation the annotation
|
|
|
|
|
* @see #registerSynthesizedAnnotation(RuntimeHints, Class)
|
|
|
|
|
*/
|
|
|
|
|
public static void registerComposableAnnotation(RuntimeHints hints, Class<?> annotationType) {
|
|
|
|
|
registerAnnotation(hints, annotationType, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void registerAnnotation(RuntimeHints hints, Class<?> annotationType, boolean withProxy) {
|
|
|
|
|
hints.reflection().registerType(annotationType, ANNOTATION_HINT);
|
|
|
|
|
Set<Class<?>> allAnnotations = new LinkedHashSet<>();
|
|
|
|
|
collectAliasedAnnotations(new HashSet<>(), allAnnotations, annotationType);
|
|
|
|
|
allAnnotations.forEach(annotation -> {
|
|
|
|
|
hints.reflection().registerType(annotation, ANNOTATION_HINT);
|
|
|
|
|
hints.proxies().registerJdkProxy(annotation, SynthesizedAnnotation.class);
|
|
|
|
|
});
|
|
|
|
|
if (!allAnnotations.isEmpty() || withProxy) {
|
|
|
|
|
hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void collectAliasedAnnotations(Set<Class<?>> seen, Set<Class<?>> types, Class<?> annotationType) {
|
|
|
|
|
if (seen.contains(annotationType) || AliasFor.class.equals(annotationType) ||
|
|
|
|
|
Reflective.class.equals(annotationType)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
seen.add(annotationType);
|
|
|
|
|
for (Method method : annotationType.getDeclaredMethods()) {
|
|
|
|
|
AliasFor aliasFor = method.getAnnotation(AliasFor.class);
|
|
|
|
|
if (aliasFor != null) {
|
|
|
|
|
Class<?> annotationAttribute = aliasFor.annotation();
|
|
|
|
|
Class<?> targetAnnotation = (annotationAttribute != Annotation.class
|
|
|
|
|
? annotationAttribute : annotationType);
|
|
|
|
|
if (types.add(targetAnnotation)) {
|
|
|
|
|
if (!targetAnnotation.equals(annotationType)) {
|
|
|
|
|
collectAliasedAnnotations(seen, types, targetAnnotation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public static void registerAnnotationIfNecessary(RuntimeHints hints, MergedAnnotation<?> annotation) {
|
|
|
|
|
if (annotation.isSynthesizable()) {
|
|
|
|
|
registerSynthesizedAnnotation(hints, annotation.getType());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|