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 7fffb38181..0000000000
--- 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 11530ced5c..b95137025d 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 9e06e5a117..0000000000
--- 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/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java b/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java
index 02a824ae88..7080bcfb0c 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 25e4e9d3f3..4b3cd9415c 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 cb842bbf7f..facf5323d0 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 5f2dd666c9..cf502e0117 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 184536a884..0dba252455 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 6b452a6706..0000000000
--- 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 0679bca86e..916c9a4920 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) {
+ 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:
+ *
+ * - 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 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 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.
+ * 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> 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);
- }
- }
- }
+ public static void registerAnnotationIfNecessary(RuntimeHints hints, MergedAnnotation> annotation) {
+ if (annotation.isSynthesizable()) {
+ registerSynthesizedAnnotation(hints, annotation.getType());
}
}
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 5a4fe9170c..e1e6672e56 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 704465d1c7..0000000000
--- 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 b4345a91ea..919ac57530 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();
- }
-
- @Test
- void registerComposableAnnotationType() {
- RuntimeHintsUtils.registerComposableAnnotation(this.hints, SampleInvoker.class);
- assertThat(this.hints.reflection().typeHints()).singleElement()
- .satisfies(annotationHint(SampleInvoker.class));
+ void registerSynthesizedAnnotation() {
+ RuntimeHintsUtils.registerSynthesizedAnnotation(this.hints, SampleInvoker.class);
assertThat(this.hints.proxies().jdkProxies()).singleElement()
.satisfies(annotationProxy(SampleInvoker.class));
}
@Test
- void registerAnnotationTypeWithLocalUseOfAliasForRegistersProxy() {
- RuntimeHintsUtils.registerAnnotation(this.hints, LocalMapping.class);
- assertThat(this.hints.reflection().typeHints()).singleElement()
- .satisfies(annotationHint(LocalMapping.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 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 {
+ @interface RetryContainer {
- @AliasFor(annotation = RetryInvoker.class)
- int value() default 5;
-
- boolean enabled() default true;
+ RetryInvoker retry();
}
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 28ba86cfa0..5d0dc97978 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 f5d262cf6c..1ea02f7b0c 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 2bad3f7585..8f6ad94bd9 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 3e6e3e2b5f..df8886f40d 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));
}
}