diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java
deleted file mode 100644
index 7fffb381819..00000000000
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHints.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2002-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.beans.factory.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.util.ClassUtils;
-
-/**
- * {@link RuntimeHintsRegistrar} for Jakarta annotations.
- *
Hints are only registered if Jakarta inject is on the classpath.
- *
- * @author Brian Clozel
- */
-class JakartaAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
-
- @Override
- public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
- if (ClassUtils.isPresent("jakarta.inject.Inject", classLoader)) {
- Stream.of("jakarta.inject.Inject", "jakarta.inject.Qualifier").forEach(annotationType ->
- RuntimeHintsUtils.registerAnnotation(hints, ClassUtils.resolveClassName(annotationType, classLoader)));
- }
- }
-
-}
diff --git a/spring-beans/src/main/resources/META-INF/spring/aot.factories b/spring-beans/src/main/resources/META-INF/spring/aot.factories
index 11530ced5cd..b95137025d8 100644
--- a/spring-beans/src/main/resources/META-INF/spring/aot.factories
+++ b/spring-beans/src/main/resources/META-INF/spring/aot.factories
@@ -1,5 +1,2 @@
org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=\
org.springframework.beans.factory.aot.BeanRegistrationsAotProcessor
-
-org.springframework.aot.hint.RuntimeHintsRegistrar=\
-org.springframework.beans.factory.annotation.JakartaAnnotationsRuntimeHints
\ No newline at end of file
diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java
deleted file mode 100644
index 9e06e5a1176..00000000000
--- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/JakartaAnnotationsRuntimeHintsTests.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2002-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.beans.factory.annotation;
-
-
-import jakarta.inject.Inject;
-import jakarta.inject.Qualifier;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.aot.hint.MemberCategory;
-import org.springframework.aot.hint.RuntimeHints;
-import org.springframework.aot.hint.RuntimeHintsRegistrar;
-import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
-import org.springframework.beans.factory.aot.AotServices;
-import org.springframework.util.ClassUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests for {@link JakartaAnnotationsRuntimeHints}.
- *
- * @author Brian Clozel
- */
-class JakartaAnnotationsRuntimeHintsTests {
-
- private final RuntimeHints hints = new RuntimeHints();
-
- @BeforeEach
- void setup() {
- AotServices.factories().load(RuntimeHintsRegistrar.class)
- .forEach(registrar -> registrar.registerHints(this.hints,
- ClassUtils.getDefaultClassLoader()));
- }
-
- @Test
- void jakartaInjectAnnotationHasHints() {
- assertThat(RuntimeHintsPredicates.reflection().onType(Inject.class)
- .withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.hints);
- }
-
- @Test
- void jakartaQualifierAnnotationHasHints() {
- assertThat(RuntimeHintsPredicates.reflection().onType(Qualifier.class)
- .withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.hints);
- }
-
-}
diff --git a/spring-context/spring-context.gradle b/spring-context/spring-context.gradle
index 1f25b74cc6e..d7e366331b3 100644
--- a/spring-context/spring-context.gradle
+++ b/spring-context/spring-context.gradle
@@ -1,7 +1,3 @@
-plugins {
- id 'org.springframework.build.runtimehints-agent'
-}
-
description = "Spring Context"
apply plugin: "kotlin"
diff --git a/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java b/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java
index 02a824ae887..7080bcfb0cb 100644
--- a/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java
+++ b/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java
@@ -142,9 +142,11 @@ class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistratio
}
private void registerAnnotationIfNecessary(RuntimeHints hints, AnnotatedElement element) {
- MergedAnnotation reflectiveAnnotation = MergedAnnotations.from(element).get(Reflective.class);
- if (reflectiveAnnotation.getDistance() > 0) {
- RuntimeHintsUtils.registerAnnotation(hints, reflectiveAnnotation.getRoot().getType());
+ MergedAnnotation reflectiveAnnotation = MergedAnnotations.from(element)
+ .get(Reflective.class);
+ MergedAnnotation> metaSource = reflectiveAnnotation.getMetaSource();
+ if (metaSource != null) {
+ RuntimeHintsUtils.registerAnnotationIfNecessary(hints, metaSource);
}
}
diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java
index 25e4e9d3f32..4b3cd9415c6 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/AsyncAnnotationBeanPostProcessor.java
@@ -25,14 +25,9 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
-import org.springframework.aot.hint.RuntimeHints;
-import org.springframework.aot.hint.RuntimeHintsRegistrar;
-import org.springframework.aot.hint.support.RuntimeHintsUtils;
import org.springframework.beans.factory.BeanFactory;
-import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.core.task.TaskExecutor;
import org.springframework.lang.Nullable;
-import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor.AsyncAnnotationRuntimeHints;
import org.springframework.util.Assert;
import org.springframework.util.function.SingletonSupplier;
@@ -67,7 +62,6 @@ import org.springframework.util.function.SingletonSupplier;
* @see ScheduledAnnotationBeanPostProcessor
*/
@SuppressWarnings("serial")
-@ImportRuntimeHints(AsyncAnnotationRuntimeHints.class)
public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor {
/**
@@ -160,13 +154,4 @@ public class AsyncAnnotationBeanPostProcessor extends AbstractBeanFactoryAwareAd
this.advisor = advisor;
}
- static class AsyncAnnotationRuntimeHints implements RuntimeHintsRegistrar {
-
- @Override
- public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
- RuntimeHintsUtils.registerAnnotation(hints, Async.class);
- }
-
- }
-
}
diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
index cb842bbf7f8..facf5323d03 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
@@ -37,9 +37,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
-import org.springframework.aot.hint.RuntimeHints;
-import org.springframework.aot.hint.RuntimeHintsRegistrar;
-import org.springframework.aot.hint.support.RuntimeHintsUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
@@ -58,7 +55,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EmbeddedValueResolverAware;
-import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.Ordered;
@@ -68,7 +64,6 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
-import org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.ScheduledAnnotationsRuntimeHints;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.FixedDelayTask;
import org.springframework.scheduling.config.FixedRateTask;
@@ -111,7 +106,6 @@ import org.springframework.util.StringValueResolver;
* @see org.springframework.scheduling.config.ScheduledTaskRegistrar
* @see AsyncAnnotationBeanPostProcessor
*/
-@ImportRuntimeHints(ScheduledAnnotationsRuntimeHints.class)
public class ScheduledAnnotationBeanPostProcessor
implements ScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor,
Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware,
@@ -611,14 +605,4 @@ public class ScheduledAnnotationBeanPostProcessor
this.registrar.destroy();
}
- static class ScheduledAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
-
- @Override
- public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
- RuntimeHintsUtils.registerAnnotation(hints, Scheduled.class);
- RuntimeHintsUtils.registerAnnotation(hints, Schedules.class);
- }
-
- }
-
}
diff --git a/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java b/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java
index 5f2dd666c91..cf502e01175 100644
--- a/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java
+++ b/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java
@@ -25,7 +25,6 @@ import java.lang.annotation.Target;
import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.GenerationContext;
-import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.annotation.Reflective;
@@ -93,19 +92,18 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests {
}
@Test
- void shouldRegisterAnnotation() {
+ void shouldNotRegisterAnnotationProxyIfNotNeeded() {
process(SampleMethodMetaAnnotatedBean.class);
RuntimeHints runtimeHints = this.generationContext.getRuntimeHints();
- assertThat(RuntimeHintsPredicates.reflection().onType(SampleInvoker.class).withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(runtimeHints);
assertThat(runtimeHints.proxies().jdkProxies()).isEmpty();
}
@Test
- void shouldRegisterAnnotationAndProxyWithAliasFor() {
+ void shouldRegisterAnnotationProxy() {
process(SampleMethodMetaAnnotatedBeanWithAlias.class);
RuntimeHints runtimeHints = this.generationContext.getRuntimeHints();
- assertThat(RuntimeHintsPredicates.reflection().onType(RetryInvoker.class).withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(runtimeHints);
- assertThat(RuntimeHintsPredicates.proxies().forInterfaces(RetryInvoker.class, SynthesizedAnnotation.class)).accepts(runtimeHints);
+ assertThat(RuntimeHintsPredicates.proxies().forInterfaces(
+ SampleInvoker.class, SynthesizedAnnotation.class)).accepts(runtimeHints);
}
@Test
@@ -236,7 +234,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests {
}
- @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+ @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective
@@ -246,7 +244,7 @@ class ReflectiveProcessorBeanRegistrationAotProcessorTests {
}
- @Target({ElementType.METHOD})
+ @Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@SampleInvoker
diff --git a/spring-core/src/main/java/org/springframework/aot/hint/annotation/Reflective.java b/spring-core/src/main/java/org/springframework/aot/hint/annotation/Reflective.java
index 184536a8845..0dba252455e 100644
--- a/spring-core/src/main/java/org/springframework/aot/hint/annotation/Reflective.java
+++ b/spring-core/src/main/java/org/springframework/aot/hint/annotation/Reflective.java
@@ -32,6 +32,9 @@ import org.springframework.core.annotation.AliasFor;
* the annotated element. By default, a reflection hint is added on the
* annotated element so that it can be discovered and invoked if necessary.
*
+ * A reflection hint is also added if necessary on the annotation that
+ * directly uses this annotation.
+ *
* @author Stephane Nicoll
* @author Sam Brannen
* @since 6.0
diff --git a/spring-core/src/main/java/org/springframework/aot/hint/support/CoreAnnotationsRuntimeHints.java b/spring-core/src/main/java/org/springframework/aot/hint/support/CoreAnnotationsRuntimeHints.java
deleted file mode 100644
index 6b452a6706e..00000000000
--- a/spring-core/src/main/java/org/springframework/aot/hint/support/CoreAnnotationsRuntimeHints.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2002-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.aot.hint.support;
-
-import java.util.stream.Stream;
-
-import org.springframework.aot.hint.RuntimeHints;
-import org.springframework.aot.hint.RuntimeHintsRegistrar;
-import org.springframework.core.annotation.AliasFor;
-import org.springframework.core.annotation.Order;
-import org.springframework.lang.Nullable;
-
-/**
- * {@link RuntimeHintsRegistrar} for core annotations.
- *
- * @author Phillip Webb
- * @since 6.0
- */
-class CoreAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
-
- @Override
- public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
- Stream.of(AliasFor.class, Order.class).forEach(annotationType ->
- RuntimeHintsUtils.registerAnnotation(hints, annotationType));
- }
-
-}
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 0679bca86e2..916c9a49206 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
@@ -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 ANNOTATION_HINT = hint ->
- hint.withMembers(MemberCategory.INVOKE_DECLARED_METHODS);
-
/**
* Register the necessary hints so that the specified annotation is visible
* at runtime.
- * 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) {
- registerAnnotation(hints, annotationType, false);
+ registerSynthesizedAnnotation(hints, annotationType);
}
/**
- * Register the necessary hints so that the specified composable
- * 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.
+ * 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:
+ *
+ * - Use {@link AliasFor} for local aliases
+ * - Has a meta-annotation that uses {@link AliasFor} for attribute overrides
+ * - Has nested annotations or arrays of annotations that are synthesizable
+ *
+ * Consider using {@link #registerAnnotationIfNecessary(RuntimeHints, MergedAnnotation)}
+ * that determines if the hints are required.
* @param hints the {@link RuntimeHints} instance to use
- * @param annotationType the composable annotation type
- * @see #registerAnnotation(RuntimeHints, Class)
+ * @param annotationType the annotation type
+ * @see SynthesizedAnnotation
*/
- public static void registerComposableAnnotation(RuntimeHints hints, Class> annotationType) {
- registerAnnotation(hints, annotationType, true);
+ public static void registerSynthesizedAnnotation(RuntimeHints hints, Class> annotationType) {
+ hints.proxies().registerJdkProxy(annotationType, SynthesizedAnnotation.class);
}
- private static void registerAnnotation(RuntimeHints hints, Class> annotationType, boolean withProxy) {
- hints.reflection().registerType(annotationType, ANNOTATION_HINT);
- Set> 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> seen, Set> 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);
- }
- }
- }
+ /**
+ * 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 annotation the annotation
+ * @see #registerSynthesizedAnnotation(RuntimeHints, Class)
+ */
+ public static void registerAnnotationIfNecessary(RuntimeHints hints, MergedAnnotation> annotation) {
+ if (annotation.isSynthesizable()) {
+ registerSynthesizedAnnotation(hints, annotation.getType());
}
}
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java
index 6d9c1bcf5de..8c909a8a5bb 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java
@@ -477,6 +477,15 @@ public interface MergedAnnotation {
*/
> T asMap(Function, T> factory, Adapt... adaptations);
+ /**
+ * Determine if this merged annotation is synthesizable.
+ * Consult the documentation for {@link #synthesize()} for an explanation
+ * of what is considered synthesizable.
+ * @return {@code true} if the mapped annotation is synthesizable
+ * @since 6.0
+ */
+ boolean isSynthesizable();
+
/**
* Create a type-safe synthesized version of this merged annotation that can
* be used directly in code.
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/MissingMergedAnnotation.java b/spring-core/src/main/java/org/springframework/core/annotation/MissingMergedAnnotation.java
index 0c7c9abad61..75966992a44 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/MissingMergedAnnotation.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/MissingMergedAnnotation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2019 the original author or authors.
+ * Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -134,6 +134,11 @@ final class MissingMergedAnnotation extends AbstractMerged
return factory.apply(this);
}
+ @Override
+ public boolean isSynthesizable() {
+ return false;
+ }
+
@Override
public String toString() {
return "(missing)";
diff --git a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java
index 7457ddd6de5..1fcbb188832 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/TypeMappedAnnotation.java
@@ -319,6 +319,17 @@ final class TypeMappedAnnotation extends AbstractMergedAnn
return value;
}
+ @Override
+ public boolean isSynthesizable() {
+ // Is this a mapped annotation for a composed annotation, and are there
+ // annotation attributes (mirrors) that need to be merged?
+ if (getDistance() > 0 && this.resolvedMirrors.length > 0) {
+ return true;
+ }
+ // Is the mapped annotation itself synthesizable?
+ return this.mapping.isSynthesizable();
+ }
+
@Override
@SuppressWarnings("unchecked")
protected A createSynthesizedAnnotation() {
@@ -347,22 +358,15 @@ final class TypeMappedAnnotation extends AbstractMergedAnn
* Determine if the supplied annotation has not already been synthesized
* and whether the mapped annotation is a composed annotation
* that needs to have its attributes merged or the mapped annotation is
- * {@linkplain AnnotationTypeMapping#isSynthesizable() synthesizable} in general.
+ * {@linkplain #isSynthesizable() synthesizable} in general.
* @param annotation the annotation to check
* @since 5.3.22
*/
private boolean isSynthesizable(Annotation annotation) {
- // Already synthesized?
if (annotation instanceof SynthesizedAnnotation) {
return false;
}
- // Is this a mapped annotation for a composed annotation, and are there
- // annotation attributes (mirrors) that need to be merged?
- if (getDistance() > 0 && this.resolvedMirrors.length > 0) {
- return true;
- }
- // Is the mapped annotation itself synthesizable?
- return this.mapping.isSynthesizable();
+ return isSynthesizable();
}
@Override
diff --git a/spring-core/src/main/resources/META-INF/spring/aot.factories b/spring-core/src/main/resources/META-INF/spring/aot.factories
index 5a4fe9170cc..e1e6672e561 100644
--- a/spring-core/src/main/resources/META-INF/spring/aot.factories
+++ b/spring-core/src/main/resources/META-INF/spring/aot.factories
@@ -1,3 +1,2 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
-org.springframework.aot.hint.support.CoreAnnotationsRuntimeHints,\
org.springframework.aot.hint.support.SpringFactoriesLoaderRuntimeHints
diff --git a/spring-core/src/test/java/org/springframework/aot/hint/support/CoreAnnotationsRuntimeHintsTests.java b/spring-core/src/test/java/org/springframework/aot/hint/support/CoreAnnotationsRuntimeHintsTests.java
deleted file mode 100644
index 704465d1c74..00000000000
--- a/spring-core/src/test/java/org/springframework/aot/hint/support/CoreAnnotationsRuntimeHintsTests.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2002-2022 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.springframework.aot.hint.support;
-
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import org.springframework.aot.hint.MemberCategory;
-import org.springframework.aot.hint.RuntimeHints;
-import org.springframework.aot.hint.RuntimeHintsRegistrar;
-import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
-import org.springframework.core.annotation.AliasFor;
-import org.springframework.core.annotation.Order;
-import org.springframework.core.io.support.SpringFactoriesLoader;
-import org.springframework.util.ClassUtils;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Tests for {@link CoreAnnotationsRuntimeHints}.
- *
- * @author Phillip Webb
- */
-class CoreAnnotationsRuntimeHintsTests {
-
- private final RuntimeHints hints = new RuntimeHints();
-
- @BeforeEach
- void setup() {
- SpringFactoriesLoader.forResourceLocation("META-INF/spring/aot.factories")
- .load(RuntimeHintsRegistrar.class).forEach(registrar -> registrar
- .registerHints(this.hints, ClassUtils.getDefaultClassLoader()));
- }
-
- @Test
- void aliasForHasHints() {
- assertThat(RuntimeHintsPredicates.reflection().onType(AliasFor.class)
- .withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.hints);
- }
-
- @Test
- void orderAnnotationHasHints() {
- assertThat(RuntimeHintsPredicates.reflection().onType(Order.class)
- .withMemberCategory(MemberCategory.INVOKE_DECLARED_METHODS)).accepts(this.hints);
- }
-
-}
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 b4345a91eaf..919ac575309 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
@@ -23,11 +23,11 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.JdkProxyHint;
-import org.springframework.aot.hint.MemberCategory;
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.MergedAnnotation;
+import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.annotation.SynthesizedAnnotation;
import static org.assertj.core.api.Assertions.assertThat;
@@ -43,75 +43,45 @@ class RuntimeHintsUtilsTests {
private final RuntimeHints hints = new RuntimeHints();
@Test
- void registerAnnotationType() {
- RuntimeHintsUtils.registerAnnotation(this.hints, SampleInvoker.class);
- assertThat(this.hints.reflection().typeHints()).singleElement()
- .satisfies(annotationHint(SampleInvoker.class));
- assertThat(this.hints.proxies().jdkProxies()).isEmpty();
+ void registerSynthesizedAnnotation() {
+ RuntimeHintsUtils.registerSynthesizedAnnotation(this.hints, SampleInvoker.class);
+ assertThat(this.hints.proxies().jdkProxies()).singleElement()
+ .satisfies(annotationProxy(SampleInvoker.class));
}
@Test
- void registerComposableAnnotationType() {
- RuntimeHintsUtils.registerComposableAnnotation(this.hints, SampleInvoker.class);
- assertThat(this.hints.reflection().typeHints()).singleElement()
- .satisfies(annotationHint(SampleInvoker.class));
- assertThat(this.hints.proxies().jdkProxies()).singleElement()
- .satisfies(annotationProxy(SampleInvoker.class));
+ void registerAnnotationIfNecessaryWithNonSynthesizedAnnotation() throws NoSuchFieldException {
+ MergedAnnotation annotation = MergedAnnotations
+ .from(TestBean.class.getField("sampleInvoker")).get(SampleInvoker.class);
+ RuntimeHintsUtils.registerAnnotationIfNecessary(this.hints, annotation);
+ 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));
+ void registerAnnotationIfNecessaryWithLocalAliases() throws NoSuchFieldException {
+ MergedAnnotation annotation = MergedAnnotations
+ .from(TestBean.class.getField("localMapping")).get(LocalMapping.class);
+ RuntimeHintsUtils.registerAnnotationIfNecessary(this.hints, annotation);
assertThat(this.hints.proxies().jdkProxies()).singleElement()
.satisfies(annotationProxy(LocalMapping.class));
}
@Test
- void registerAnnotationTypeProxyRegistersJdkProxies() {
- RuntimeHintsUtils.registerAnnotation(this.hints, RetryInvoker.class);
- assertThat(this.hints.reflection().typeHints())
- .anySatisfy(annotationHint(RetryInvoker.class))
- .anySatisfy(annotationHint(SampleInvoker.class))
- .hasSize(2);
- assertThat(this.hints.proxies().jdkProxies())
- .anySatisfy(annotationProxy(RetryInvoker.class))
- .anySatisfy(annotationProxy(SampleInvoker.class))
- .hasSize(2);
- }
-
- @Test // gh-28953
- void registerAnnotationForAliasForShouldNotRegisterSynthesizedAnnotationProxy() {
- RuntimeHintsUtils.registerAnnotation(this.hints, AliasFor.class);
- assertThat(this.hints.reflection().typeHints()).singleElement()
- .satisfies(annotationHint(AliasFor.class));
- assertThat(this.hints.proxies().jdkProxies()).isEmpty();
+ void registerAnnotationIfNecessaryWithMetaAttributeOverride() throws NoSuchFieldException {
+ MergedAnnotation annotation = MergedAnnotations
+ .from(TestBean.class.getField("retryInvoker")).get(SampleInvoker.class);
+ RuntimeHintsUtils.registerAnnotationIfNecessary(this.hints, annotation);
+ assertThat(this.hints.proxies().jdkProxies()).singleElement()
+ .satisfies(annotationProxy(SampleInvoker.class));
}
@Test
- void registerAnnotationTypeWhereUsedAsAMetaAnnotationRegistersHierarchy() {
- RuntimeHintsUtils.registerAnnotation(this.hints, RetryWithEnabledFlagInvoker.class);
- assertThat(this.hints.reflection().typeHints())
- .anySatisfy(annotationHint(RetryWithEnabledFlagInvoker.class))
- .anySatisfy(annotationHint(RetryInvoker.class))
- .anySatisfy(annotationHint(SampleInvoker.class))
- .hasSize(3);
- assertThat(this.hints.proxies().jdkProxies())
- .anySatisfy(annotationProxy(RetryWithEnabledFlagInvoker.class))
- .anySatisfy(annotationProxy(RetryInvoker.class))
- .anySatisfy(annotationProxy(SampleInvoker.class))
- .hasSize(3);
- }
-
- private Consumer annotationHint(Class> type) {
- return typeHint -> {
- assertThat(typeHint.getType()).isEqualTo(TypeReference.of(type));
- assertThat(typeHint.constructors()).isEmpty();
- assertThat(typeHint.fields()).isEmpty();
- assertThat(typeHint.methods()).isEmpty();
- assertThat(typeHint.getMemberCategories()).containsOnly(MemberCategory.INVOKE_DECLARED_METHODS);
- };
+ void registerAnnotationIfNecessaryWithSynthesizedAttribute() throws NoSuchFieldException {
+ MergedAnnotation annotation = MergedAnnotations
+ .from(TestBean.class.getField("retryContainer")).get(RetryContainer.class);
+ RuntimeHintsUtils.registerAnnotationIfNecessary(this.hints, annotation);
+ assertThat(this.hints.proxies().jdkProxies()).singleElement()
+ .satisfies(annotationProxy(RetryContainer.class));
}
private Consumer annotationProxy(Class> type) {
@@ -120,6 +90,22 @@ class RuntimeHintsUtilsTests {
}
+ static class TestBean {
+
+ @SampleInvoker
+ public String sampleInvoker;
+
+ @LocalMapping
+ public String localMapping;
+
+ @RetryInvoker
+ public String retryInvoker;
+
+ @RetryContainer(retry = @RetryInvoker(3))
+ public String retryContainer;
+
+ }
+
@Retention(RetentionPolicy.RUNTIME)
@interface LocalMapping {
@@ -149,13 +135,9 @@ class RuntimeHintsUtilsTests {
}
@Retention(RetentionPolicy.RUNTIME)
- @RetryInvoker
- @interface RetryWithEnabledFlagInvoker {
-
- @AliasFor(annotation = RetryInvoker.class)
- int value() default 5;
+ @interface RetryContainer {
- boolean enabled() default true;
+ RetryInvoker retry();
}
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java
index 0b78f39e378..94efc1e2796 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java
@@ -1504,6 +1504,13 @@ class MergedAnnotationsTests {
assertThat(synthesizedComponent.value()).isEqualTo("webController");
}
+ @Test
+ void isSynthesizableWithoutAttributeAliases() throws Exception {
+ Component component = WebController.class.getAnnotation(Component.class);
+ assertThat(component).isNotNull();
+ assertThat(MergedAnnotation.from(component).isSynthesizable()).isFalse();
+ }
+
@Test
void synthesizeAlreadySynthesized() throws Exception {
Method method = WebController.class.getMethod("handleMappedWithValueAttribute");
@@ -1567,10 +1574,16 @@ class MergedAnnotationsTests {
void synthesizeShouldNotSynthesizeNonsynthesizableAnnotationsWhenUsingMergedAnnotationsFromApi() {
MergedAnnotations mergedAnnotations = MergedAnnotations.from(SecurityConfig.class);
- EnableWebSecurity enableWebSecurity = mergedAnnotations.get(EnableWebSecurity.class).synthesize();
+ MergedAnnotation enableWebSecurityAnnotation =
+ mergedAnnotations.get(EnableWebSecurity.class);
+ assertThat(enableWebSecurityAnnotation.isSynthesizable()).isFalse();
+ EnableWebSecurity enableWebSecurity = enableWebSecurityAnnotation.synthesize();
assertThat(enableWebSecurity).isNotInstanceOf(SynthesizedAnnotation.class);
- EnableGlobalAuthentication enableGlobalAuthentication = mergedAnnotations.get(EnableGlobalAuthentication.class).synthesize();
+ MergedAnnotation enableGlobalAuthenticationMergedAnnotation =
+ mergedAnnotations.get(EnableGlobalAuthentication.class);
+ assertThat(enableGlobalAuthenticationMergedAnnotation.isSynthesizable()).isFalse();
+ EnableGlobalAuthentication enableGlobalAuthentication = enableGlobalAuthenticationMergedAnnotation.synthesize();
assertThat(enableGlobalAuthentication).isNotInstanceOf(SynthesizedAnnotation.class);
}
@@ -1718,8 +1731,9 @@ class MergedAnnotationsTests {
ImplicitAliasesTestConfiguration config = clazz.getAnnotation(
ImplicitAliasesTestConfiguration.class);
assertThat(config).isNotNull();
- ImplicitAliasesTestConfiguration synthesized = MergedAnnotation.from(
- config).synthesize();
+ MergedAnnotation mergedAnnotation = MergedAnnotation.from(config);
+ assertThat(mergedAnnotation.isSynthesizable()).isTrue();
+ ImplicitAliasesTestConfiguration synthesized = mergedAnnotation.synthesize();
assertThat(synthesized).isInstanceOf(SynthesizedAnnotation.class);
assertThat(synthesized.value()).isEqualTo(expected);
assertThat(synthesized.location1()).isEqualTo(expected);
@@ -1746,8 +1760,11 @@ class MergedAnnotationsTests {
ImplicitAliasesWithImpliedAliasNamesOmittedTestConfiguration config = clazz.getAnnotation(
ImplicitAliasesWithImpliedAliasNamesOmittedTestConfiguration.class);
assertThat(config).isNotNull();
+ MergedAnnotation mergedAnnotation =
+ MergedAnnotation.from(config);
+ assertThat(mergedAnnotation.isSynthesizable()).isTrue();
ImplicitAliasesWithImpliedAliasNamesOmittedTestConfiguration synthesized =
- MergedAnnotation.from(config).synthesize();
+ mergedAnnotation.synthesize();
assertThat(synthesized).isInstanceOf(SynthesizedAnnotation.class);
assertThat(synthesized.value()).isEqualTo(expected);
assertThat(synthesized.location()).isEqualTo(expected);
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MissingMergedAnnotationTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MissingMergedAnnotationTests.java
index 151b31f3ae0..eb391f4c1c9 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/MissingMergedAnnotationTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/MissingMergedAnnotationTests.java
@@ -255,6 +255,11 @@ class MissingMergedAnnotationTests {
assertThat(this.missing.getDefaultValue("value", Integer.class)).isEmpty();
}
+ @Test
+ void isSynthesizableReturnsFalse() {
+ assertThat(this.missing.isSynthesizable()).isFalse();
+ }
+
@Test
void synthesizeThrowsNoSuchElementException() {
assertThatNoSuchElementException().isThrownBy(this.missing::synthesize);
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessagingAnnotationsRuntimeHints.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessagingAnnotationsRuntimeHints.java
index 28ba86cfa0a..5d0dc97978f 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessagingAnnotationsRuntimeHints.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessagingAnnotationsRuntimeHints.java
@@ -35,8 +35,7 @@ public class MessagingAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
- Stream.of(Controller.class, DestinationVariable.class, Header.class, Headers.class,
- MessageExceptionHandler.class, MessageMapping.class, Payload.class, SendTo.class).forEach(
- annotationType -> RuntimeHintsUtils.registerAnnotation(hints, annotationType));
+ Stream.of(Controller.class, Header.class, Headers.class, Payload.class).forEach(annotationType ->
+ RuntimeHintsUtils.registerSynthesizedAnnotation(hints, annotationType));
}
}
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SimpAnnotationsRuntimeHints.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SimpAnnotationsRuntimeHints.java
index f5d262cf6c2..1ea02f7b0c3 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SimpAnnotationsRuntimeHints.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SimpAnnotationsRuntimeHints.java
@@ -16,8 +16,6 @@
package org.springframework.messaging.simp.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;
@@ -33,7 +31,6 @@ public class SimpAnnotationsRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
- Stream.of(SendToUser.class, SubscribeMapping.class).forEach(
- annotationType -> RuntimeHintsUtils.registerAnnotation(hints, annotationType));
+ RuntimeHintsUtils.registerSynthesizedAnnotation(hints, SendToUser.class);
}
}
diff --git a/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java b/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java
index 2bad3f7585e..8f6ad94bd9d 100644
--- a/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java
+++ b/spring-tx/src/main/java/org/springframework/transaction/annotation/TransactionRuntimeHints.java
@@ -37,7 +37,7 @@ class TransactionRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
- RuntimeHintsUtils.registerAnnotation(hints, Transactional.class);
+ RuntimeHintsUtils.registerSynthesizedAnnotation(hints, Transactional.class);
hints.reflection()
.registerTypes(List.of(
TypeReference.of(Isolation.class),
diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/WebAnnotationsRuntimeHintsRegistrar.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/WebAnnotationsRuntimeHintsRegistrar.java
index 3e6e3e2b5f4..df8886f40df 100644
--- a/spring-web/src/main/java/org/springframework/web/bind/annotation/WebAnnotationsRuntimeHintsRegistrar.java
+++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/WebAnnotationsRuntimeHintsRegistrar.java
@@ -36,15 +36,12 @@ public final class WebAnnotationsRuntimeHintsRegistrar implements RuntimeHintsRe
@Override
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
Stream.of(Controller.class, ControllerAdvice.class, CookieValue.class,
- CrossOrigin.class, DeleteMapping.class, ExceptionHandler.class,
- GetMapping.class, InitBinder.class, Mapping.class, MatrixVariable.class,
- ModelAttribute.class, PatchMapping.class, PathVariable.class,
- PostMapping.class, PutMapping.class, RequestAttribute.class,
- RequestBody.class, RequestHeader.class, RequestMapping.class,
- RequestParam.class, RequestPart.class, ResponseBody.class,
- ResponseStatus.class, RestController.class, RestControllerAdvice.class,
- SessionAttribute.class, SessionAttributes.class).forEach(
- annotationType -> RuntimeHintsUtils.registerAnnotation(hints, annotationType));
+ CrossOrigin.class, MatrixVariable.class, ModelAttribute.class,
+ PathVariable.class, RequestAttribute.class, RequestHeader.class,
+ RequestMapping.class, RequestParam.class, RequestPart.class,
+ ResponseStatus.class, SessionAttribute.class, SessionAttributes.class)
+ .forEach(annotationType ->
+ RuntimeHintsUtils.registerSynthesizedAnnotation(hints, annotationType));
}
}