From eb91d21ada941d041e242bc1b32a1e909aed7a8d Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 13 Nov 2022 16:01:37 +0100 Subject: [PATCH] Polishing --- .../SchedulerFactoryBeanRuntimeHints.java | 2 ++ .../annotation/ImportRuntimeHints.java | 19 ++++++++++++------- .../aot/hint/annotation/Reflective.java | 3 ++- .../hint/annotation/ReflectiveProcessor.java | 4 ++++ .../ReflectiveRuntimeHintsRegistrar.java | 6 +++--- .../RegisterReflectionForBinding.java | 18 +++++++++--------- ...RegisterReflectionForBindingProcessor.java | 4 +++- .../MessageMappingReflectiveProcessor.java | 14 +++++++++----- .../context/aot/TestContextAotGenerator.java | 11 ++++++++--- .../aot/TestRuntimeHintsRegistrar.java | 6 ++++++ .../ControllerMappingReflectiveProcessor.java | 14 ++++++++------ .../ExceptionHandlerReflectiveProcessor.java | 1 + .../HttpExchangeReflectiveProcessor.java | 3 ++- 13 files changed, 69 insertions(+), 36 deletions(-) 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) type) .distinct() + .map(type -> (Class) 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: + * *

* * @author Sebastien Deleuze @@ -49,6 +50,7 @@ class MessageMappingReflectiveProcessor implements ReflectiveProcessor { private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + @Override public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { if (element instanceof Class type) { @@ -99,6 +101,8 @@ class MessageMappingReflectiveProcessor implements ReflectiveProcessor { @Nullable protected Type getMessageType(MethodParameter parameter) { MethodParameter nestedParameter = parameter.nested(); - return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ? null : nestedParameter.getNestedParameterType()); + return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ? + null : nestedParameter.getNestedParameterType()); } + } diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java index d51569f22c0..b8d40fb3aed 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java @@ -137,15 +137,20 @@ public class TestContextAotGenerator { mergedConfigMappings.add(mergedConfig, testClass); collectRuntimeHintsRegistrarClasses(testClass, coreRuntimeHintsRegistrarClasses); reflectiveRuntimeHintsRegistrar.registerRuntimeHints(this.runtimeHints, testClass); - this.testRuntimeHintsRegistrars.forEach(registrar -> - registrar.registerHints(this.runtimeHints, testClass, classLoader)); + this.testRuntimeHintsRegistrars.forEach(registrar -> { + if (logger.isTraceEnabled()) { + logger.trace("Processing RuntimeHints contribution from class [%s]" + .formatted(registrar.getClass().getCanonicalName())); + } + registrar.registerHints(this.runtimeHints, testClass, classLoader); + }); }); coreRuntimeHintsRegistrarClasses.stream() .map(BeanUtils::instantiateClass) .forEach(registrar -> { if (logger.isTraceEnabled()) { - logger.trace("Processing RuntimeHints contribution from test class [%s]" + logger.trace("Processing RuntimeHints contribution from class [%s]" .formatted(registrar.getClass().getCanonicalName())); } registrar.registerHints(this.runtimeHints, classLoader); diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestRuntimeHintsRegistrar.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestRuntimeHintsRegistrar.java index e347d8cd655..22a87c769b7 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestRuntimeHintsRegistrar.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestRuntimeHintsRegistrar.java @@ -34,6 +34,12 @@ import org.springframework.aot.hint.RuntimeHints; * specific to particular test classes, favor implementing {@code RuntimeHintsRegistrar} * over this API. * + *

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: + * *

* * @author Stephane Nicoll @@ -49,6 +50,7 @@ class ControllerMappingReflectiveProcessor implements ReflectiveProcessor { private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + @Override public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { if (element instanceof Class type) { @@ -98,8 +100,8 @@ class ControllerMappingReflectiveProcessor implements ReflectiveProcessor { @Nullable private Type getHttpEntityType(MethodParameter parameter) { MethodParameter nestedParameter = parameter.nested(); - return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() - ? null : nestedParameter.getNestedParameterType()); + return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ? + null : nestedParameter.getNestedParameterType()); } } diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java index 448392ea759..63be5695912 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java @@ -37,4 +37,5 @@ class ExceptionHandlerReflectiveProcessor extends ControllerMappingReflectivePro } super.registerReturnTypeHints(hints, returnTypeParameter); } + } diff --git a/spring-web/src/main/java/org/springframework/web/service/annotation/HttpExchangeReflectiveProcessor.java b/spring-web/src/main/java/org/springframework/web/service/annotation/HttpExchangeReflectiveProcessor.java index 16e24ab6b89..128d821121c 100644 --- a/spring-web/src/main/java/org/springframework/web/service/annotation/HttpExchangeReflectiveProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/service/annotation/HttpExchangeReflectiveProcessor.java @@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RequestBody; /** * {@link ReflectiveProcessor} implementation for {@link HttpExchange @HttpExchange} - * and annotated methods. On top of registering reflection hints for invoking + * annotated methods. In addition to registering reflection hints for invoking * the annotated method, this implementation handles reflection-based * binding for return types and parameters annotated with {@link RequestBody}. * @@ -40,6 +40,7 @@ class HttpExchangeReflectiveProcessor implements ReflectiveProcessor { private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); + @Override public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { if (element instanceof Method method) {