diff --git a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java index daf2b17d358..c2d727a4558 100644 --- a/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java +++ b/spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java @@ -38,6 +38,7 @@ class SchedulerFactoryBeanRuntimeHints implements RuntimeHintsRegistrar { private final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar(); + @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { if (!ClassUtils.isPresent(SCHEDULER_FACTORY_CLASS_NAME, classLoader)) { @@ -53,4 +54,5 @@ class SchedulerFactoryBeanRuntimeHints implements RuntimeHintsRegistrar { private void typeHint(Builder typeHint) { typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS).onReachableType(SchedulerFactoryBean.class); } + } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ImportRuntimeHints.java b/spring-context/src/main/java/org/springframework/context/annotation/ImportRuntimeHints.java index d33550db62c..bc3d4992c54 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ImportRuntimeHints.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ImportRuntimeHints.java @@ -29,7 +29,7 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar; * should be processed. * *
Unlike declaring {@link RuntimeHintsRegistrar} using - * {@code spring/aot.factories}, this annotation allows for more flexible + * {@code META-INF/spring/aot.factories}, this annotation allows for more flexible * registration where it is only processed if the annotated component or bean * method is actually registered in the bean factory. To illustrate this * behavior, consider the following example: @@ -47,19 +47,24 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar; * * } * - * If the configuration class above is processed, {@code MyHints} will be - * contributed only if {@code MyCondition} matches. If it does not, and - * therefore {@code MyService} is not defined as a bean, the hints will + *
If the configuration class above is processed, {@code MyHints} will be + * contributed only if {@code MyCondition} matches. If the condition does not + * match, {@code MyService} will not be defined as a bean and the hints will * not be processed either. * - *
If several components refer to the same {@link RuntimeHintsRegistrar} - * implementation, it is invoked only once for a given bean factory - * processing. + *
{@code @ImportRuntimeHints} can also be applied to any test class that uses + * the Spring TestContext Framework to load an {@code ApplicationContext}. + * + *
If several components or test classes refer to the same {@link RuntimeHintsRegistrar} + * implementation, the registrar will only be invoked once for the given bean factory + * processing or test suite. * * @author Brian Clozel * @author Stephane Nicoll * @since 6.0 * @see org.springframework.aot.hint.RuntimeHints + * @see org.springframework.aot.hint.annotation.Reflective + * @see org.springframework.aot.hint.annotation.RegisterReflectionForBinding */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) 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 6a13995c1f4..e12ceae9d49 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 @@ -29,7 +29,7 @@ import org.springframework.core.annotation.AliasFor; * *
When present, either directly or as a meta-annotation, this annotation * triggers the configured {@linkplain ReflectiveProcessor processors} against - * the annotated element. By default, a reflection hint is added on the + * the annotated element. By default, a reflection hint is registered for the * annotated element so that it can be discovered and invoked if necessary. * * @author Stephane Nicoll @@ -37,6 +37,7 @@ import org.springframework.core.annotation.AliasFor; * @since 6.0 * @see SimpleReflectiveProcessor * @see ReflectiveRuntimeHintsRegistrar + * @see RegisterReflectionForBinding @RegisterReflectionForBinding */ @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD }) diff --git a/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveProcessor.java b/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveProcessor.java index a753d385628..74d1b1385f3 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveProcessor.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveProcessor.java @@ -24,8 +24,12 @@ import org.springframework.aot.hint.ReflectionHints; * Process an {@link AnnotatedElement} and register the necessary reflection * hints for it. * + *
{@code ReflectiveProcessor} implementations are registered via + * {@link Reflective#processors() @Reflective(processors = ...)}. + * * @author Stephane Nicoll * @since 6.0 + * @see Reflective @Reflective */ public interface ReflectiveProcessor { diff --git a/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java b/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java index f860745a50a..61e80a3fa2e 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java @@ -96,12 +96,12 @@ public class ReflectiveRuntimeHintsRegistrar { .stream(Reflective.class) .map(annotation -> annotation.getClassArray("value")) .flatMap(Arrays::stream) - .map(type -> (Class extends ReflectiveProcessor>) type) .distinct() + .map(type -> (Class extends ReflectiveProcessor>) type) .map(processorClass -> this.processors.computeIfAbsent(processorClass, this::instantiateClass)) .toList(); - ReflectiveProcessor processorToUse = (processors.size() == 1 ? processors.get(0) - : new DelegatingReflectiveProcessor(processors)); + ReflectiveProcessor processorToUse = (processors.size() == 1 ? processors.get(0) : + new DelegatingReflectiveProcessor(processors)); return new Entry(element, processorToUse); } diff --git a/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBinding.java b/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBinding.java index 7c2f8e0cbb1..d0a5b9c98ba 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBinding.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBinding.java @@ -25,25 +25,24 @@ import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; /** - * Indicate that the classes specified in the annotation attributes require some + * Indicates that the classes specified in the annotation attributes require some * reflection hints for binding or reflection-based serialization purposes. For each * class specified, hints on constructors, fields, properties, record components, * including types transitively used on properties and record components are registered. * At least one class must be specified in the {@code value} or {@code classes} annotation * attributes. * - *
The annotated element can be a configuration class, for example: + *
The annotated element can be a configuration class — for example: * *
* @Configuration
* @RegisterReflectionForBinding({ Foo.class, Bar.class })
* public class MyConfig {
- *
* // ...
* }
*
- * The annotated element can also be any Spring bean class, constructor, field, or method. - * For example: + *
The annotated element can be any Spring bean class, constructor, field, + * or method — for example: * *
* @Service @@ -56,9 +55,13 @@ import org.springframework.core.annotation.AliasFor; * * }* + *
The annotated element can also be any test class that uses the Spring + * TestContext Framework to load an {@code ApplicationContext}. + * * @author Sebastien Deleuze * @since 6.0 * @see org.springframework.aot.hint.BindingReflectionHintsRegistrar + * @see Reflective @Reflective */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @@ -67,10 +70,7 @@ import org.springframework.core.annotation.AliasFor; public @interface RegisterReflectionForBinding { /** - * Classes for which reflection hints should be registered. - *
At least one class must be specified either via {@link #value} or - * {@link #classes}. - * @see #classes() + * Alias for {@link #classes()}. */ @AliasFor("classes") Class>[] value() default {}; diff --git a/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBindingProcessor.java b/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBindingProcessor.java index 311204c3bfa..06e79ee53af 100644 --- a/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBindingProcessor.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBindingProcessor.java @@ -36,9 +36,11 @@ public class RegisterReflectionForBindingProcessor implements ReflectiveProcesso private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + @Override public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { - RegisterReflectionForBinding registerReflection = AnnotationUtils.getAnnotation(element, RegisterReflectionForBinding.class); + RegisterReflectionForBinding registerReflection = + AnnotationUtils.getAnnotation(element, RegisterReflectionForBinding.class); if (registerReflection != null) { Class>[] classes = registerReflection.classes(); Assert.state(classes.length != 0, () -> "A least one class should be specified in " + diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMappingReflectiveProcessor.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMappingReflectiveProcessor.java index 06d67a8931a..cdfed1ff7c1 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMappingReflectiveProcessor.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMappingReflectiveProcessor.java @@ -34,12 +34,13 @@ import org.springframework.messaging.support.MessageHeaderAccessor; /** * {@link ReflectiveProcessor} implementation for {@link MessageMapping} - * annotated types. On top of registering reflection hints for invoking + * annotated types. In addition to registering reflection hints for invoking * the annotated method, this implementation handles: + * *
As an alternative to implementing and registering a {@code TestRuntimeHintsRegistrar}, + * you may choose to annotate a test class with + * {@link org.springframework.aot.hint.annotation.Reflective @Reflective}, + * {@link org.springframework.aot.hint.annotation.RegisterReflectionForBinding @RegisterReflectionForBinding}, + * or {@link org.springframework.context.annotation.ImportRuntimeHints @ImportRuntimeHints}. + * * @author Sam Brannen * @since 6.0 * @see org.springframework.aot.hint.RuntimeHintsRegistrar diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerMappingReflectiveProcessor.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerMappingReflectiveProcessor.java index 878f3af049e..fede4370150 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerMappingReflectiveProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerMappingReflectiveProcessor.java @@ -33,12 +33,13 @@ import org.springframework.stereotype.Controller; /** * {@link ReflectiveProcessor} implementation for {@link Controller} and - * controller-specific annotated methods. On top of registering reflection + * controller-specific annotated methods. In addition to registering reflection * hints for invoking the annotated method, this implementation handles: + * *