Browse Source

Polishing

pull/29492/head
Sam Brannen 3 years ago
parent
commit
eb91d21ada
  1. 2
      spring-context-support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBeanRuntimeHints.java
  2. 19
      spring-context/src/main/java/org/springframework/context/annotation/ImportRuntimeHints.java
  3. 3
      spring-core/src/main/java/org/springframework/aot/hint/annotation/Reflective.java
  4. 4
      spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveProcessor.java
  5. 6
      spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java
  6. 18
      spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBinding.java
  7. 4
      spring-core/src/main/java/org/springframework/aot/hint/annotation/RegisterReflectionForBindingProcessor.java
  8. 14
      spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMappingReflectiveProcessor.java
  9. 11
      spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java
  10. 6
      spring-test/src/main/java/org/springframework/test/context/aot/TestRuntimeHintsRegistrar.java
  11. 14
      spring-web/src/main/java/org/springframework/web/bind/annotation/ControllerMappingReflectiveProcessor.java
  12. 1
      spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java
  13. 3
      spring-web/src/main/java/org/springframework/web/service/annotation/HttpExchangeReflectiveProcessor.java

2
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(); private final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();
@Override @Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) { public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (!ClassUtils.isPresent(SCHEDULER_FACTORY_CLASS_NAME, classLoader)) { if (!ClassUtils.isPresent(SCHEDULER_FACTORY_CLASS_NAME, classLoader)) {
@ -53,4 +54,5 @@ class SchedulerFactoryBeanRuntimeHints implements RuntimeHintsRegistrar {
private void typeHint(Builder typeHint) { private void typeHint(Builder typeHint) {
typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS).onReachableType(SchedulerFactoryBean.class); typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS).onReachableType(SchedulerFactoryBean.class);
} }
} }

19
spring-context/src/main/java/org/springframework/context/annotation/ImportRuntimeHints.java

@ -29,7 +29,7 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar;
* should be processed. * should be processed.
* *
* <p>Unlike declaring {@link RuntimeHintsRegistrar} using * <p>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 * registration where it is only processed if the annotated component or bean
* method is actually registered in the bean factory. To illustrate this * method is actually registered in the bean factory. To illustrate this
* behavior, consider the following example: * behavior, consider the following example:
@ -47,19 +47,24 @@ import org.springframework.aot.hint.RuntimeHintsRegistrar;
* *
* }</pre> * }</pre>
* *
* If the configuration class above is processed, {@code MyHints} will be * <p>If the configuration class above is processed, {@code MyHints} will be
* contributed only if {@code MyCondition} matches. If it does not, and * contributed only if {@code MyCondition} matches. If the condition does not
* therefore {@code MyService} is not defined as a bean, the hints will * match, {@code MyService} will not be defined as a bean and the hints will
* not be processed either. * not be processed either.
* *
* <p>If several components refer to the same {@link RuntimeHintsRegistrar} * <p>{@code @ImportRuntimeHints} can also be applied to any test class that uses
* implementation, it is invoked only once for a given bean factory * the <em>Spring TestContext Framework</em> to load an {@code ApplicationContext}.
* processing. *
* <p>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 Brian Clozel
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 6.0 * @since 6.0
* @see org.springframework.aot.hint.RuntimeHints * @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}) @Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)

3
spring-core/src/main/java/org/springframework/aot/hint/annotation/Reflective.java

@ -29,7 +29,7 @@ import org.springframework.core.annotation.AliasFor;
* *
* <p>When present, either directly or as a meta-annotation, this annotation * <p>When present, either directly or as a meta-annotation, this annotation
* triggers the configured {@linkplain ReflectiveProcessor processors} against * 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. * annotated element so that it can be discovered and invoked if necessary.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
@ -37,6 +37,7 @@ import org.springframework.core.annotation.AliasFor;
* @since 6.0 * @since 6.0
* @see SimpleReflectiveProcessor * @see SimpleReflectiveProcessor
* @see ReflectiveRuntimeHintsRegistrar * @see ReflectiveRuntimeHintsRegistrar
* @see RegisterReflectionForBinding @RegisterReflectionForBinding
*/ */
@Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.CONSTRUCTOR, @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.CONSTRUCTOR,
ElementType.FIELD, ElementType.METHOD }) ElementType.FIELD, ElementType.METHOD })

4
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 * Process an {@link AnnotatedElement} and register the necessary reflection
* hints for it. * hints for it.
* *
* <p>{@code ReflectiveProcessor} implementations are registered via
* {@link Reflective#processors() @Reflective(processors = ...)}.
*
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 6.0 * @since 6.0
* @see Reflective @Reflective
*/ */
public interface ReflectiveProcessor { public interface ReflectiveProcessor {

6
spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java

@ -96,12 +96,12 @@ public class ReflectiveRuntimeHintsRegistrar {
.stream(Reflective.class) .stream(Reflective.class)
.map(annotation -> annotation.getClassArray("value")) .map(annotation -> annotation.getClassArray("value"))
.flatMap(Arrays::stream) .flatMap(Arrays::stream)
.map(type -> (Class<? extends ReflectiveProcessor>) type)
.distinct() .distinct()
.map(type -> (Class<? extends ReflectiveProcessor>) type)
.map(processorClass -> this.processors.computeIfAbsent(processorClass, this::instantiateClass)) .map(processorClass -> this.processors.computeIfAbsent(processorClass, this::instantiateClass))
.toList(); .toList();
ReflectiveProcessor processorToUse = (processors.size() == 1 ? processors.get(0) ReflectiveProcessor processorToUse = (processors.size() == 1 ? processors.get(0) :
: new DelegatingReflectiveProcessor(processors)); new DelegatingReflectiveProcessor(processors));
return new Entry(element, processorToUse); return new Entry(element, processorToUse);
} }

18
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; 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 * reflection hints for binding or reflection-based serialization purposes. For each
* class specified, hints on constructors, fields, properties, record components, * class specified, hints on constructors, fields, properties, record components,
* including types transitively used on properties and record components are registered. * 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 * At least one class must be specified in the {@code value} or {@code classes} annotation
* attributes. * attributes.
* *
* <p>The annotated element can be a configuration class, for example: * <p>The annotated element can be a configuration class &mdash; for example:
* *
* <pre class="code"> * <pre class="code">
* &#064;Configuration * &#064;Configuration
* &#064;RegisterReflectionForBinding({ Foo.class, Bar.class }) * &#064;RegisterReflectionForBinding({ Foo.class, Bar.class })
* public class MyConfig { * public class MyConfig {
*
* // ... * // ...
* }</pre> * }</pre>
* *
* <p>The annotated element can also be any Spring bean class, constructor, field, or method. * <p>The annotated element can be any Spring bean class, constructor, field,
* For example: * or method &mdash; for example:
* *
* <pre class="code"> * <pre class="code">
* &#064;Service * &#064;Service
@ -56,9 +55,13 @@ import org.springframework.core.annotation.AliasFor;
* *
* }</pre> * }</pre>
* *
* <p>The annotated element can also be any test class that uses the <em>Spring
* TestContext Framework</em> to load an {@code ApplicationContext}.
*
* @author Sebastien Deleuze * @author Sebastien Deleuze
* @since 6.0 * @since 6.0
* @see org.springframework.aot.hint.BindingReflectionHintsRegistrar * @see org.springframework.aot.hint.BindingReflectionHintsRegistrar
* @see Reflective @Reflective
*/ */
@Target({ ElementType.TYPE, ElementType.METHOD }) @Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ -67,10 +70,7 @@ import org.springframework.core.annotation.AliasFor;
public @interface RegisterReflectionForBinding { public @interface RegisterReflectionForBinding {
/** /**
* Classes for which reflection hints should be registered. * Alias for {@link #classes()}.
* <p>At least one class must be specified either via {@link #value} or
* {@link #classes}.
* @see #classes()
*/ */
@AliasFor("classes") @AliasFor("classes")
Class<?>[] value() default {}; Class<?>[] value() default {};

4
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(); private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override @Override
public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
RegisterReflectionForBinding registerReflection = AnnotationUtils.getAnnotation(element, RegisterReflectionForBinding.class); RegisterReflectionForBinding registerReflection =
AnnotationUtils.getAnnotation(element, RegisterReflectionForBinding.class);
if (registerReflection != null) { if (registerReflection != null) {
Class<?>[] classes = registerReflection.classes(); Class<?>[] classes = registerReflection.classes();
Assert.state(classes.length != 0, () -> "A least one class should be specified in " + Assert.state(classes.length != 0, () -> "A least one class should be specified in " +

14
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} * {@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: * the annotated method, this implementation handles:
*
* <ul> * <ul>
* <li>Return types.</li> * <li>Return types</li>
* <li>Parameters identified as potential payload.</li> * <li>Parameters identified as potential payloads</li>
* <li>{@link Message} parameters.</li> * <li>{@link Message} parameters</li>
* </ul> * </ul>
* *
* @author Sebastien Deleuze * @author Sebastien Deleuze
@ -49,6 +50,7 @@ class MessageMappingReflectiveProcessor implements ReflectiveProcessor {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override @Override
public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
if (element instanceof Class<?> type) { if (element instanceof Class<?> type) {
@ -99,6 +101,8 @@ class MessageMappingReflectiveProcessor implements ReflectiveProcessor {
@Nullable @Nullable
protected Type getMessageType(MethodParameter parameter) { protected Type getMessageType(MethodParameter parameter) {
MethodParameter nestedParameter = parameter.nested(); MethodParameter nestedParameter = parameter.nested();
return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ? null : nestedParameter.getNestedParameterType()); return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ?
null : nestedParameter.getNestedParameterType());
} }
} }

11
spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java

@ -137,15 +137,20 @@ public class TestContextAotGenerator {
mergedConfigMappings.add(mergedConfig, testClass); mergedConfigMappings.add(mergedConfig, testClass);
collectRuntimeHintsRegistrarClasses(testClass, coreRuntimeHintsRegistrarClasses); collectRuntimeHintsRegistrarClasses(testClass, coreRuntimeHintsRegistrarClasses);
reflectiveRuntimeHintsRegistrar.registerRuntimeHints(this.runtimeHints, testClass); reflectiveRuntimeHintsRegistrar.registerRuntimeHints(this.runtimeHints, testClass);
this.testRuntimeHintsRegistrars.forEach(registrar -> this.testRuntimeHintsRegistrars.forEach(registrar -> {
registrar.registerHints(this.runtimeHints, testClass, classLoader)); if (logger.isTraceEnabled()) {
logger.trace("Processing RuntimeHints contribution from class [%s]"
.formatted(registrar.getClass().getCanonicalName()));
}
registrar.registerHints(this.runtimeHints, testClass, classLoader);
});
}); });
coreRuntimeHintsRegistrarClasses.stream() coreRuntimeHintsRegistrarClasses.stream()
.map(BeanUtils::instantiateClass) .map(BeanUtils::instantiateClass)
.forEach(registrar -> { .forEach(registrar -> {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Processing RuntimeHints contribution from test class [%s]" logger.trace("Processing RuntimeHints contribution from class [%s]"
.formatted(registrar.getClass().getCanonicalName())); .formatted(registrar.getClass().getCanonicalName()));
} }
registrar.registerHints(this.runtimeHints, classLoader); registrar.registerHints(this.runtimeHints, classLoader);

6
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} * specific to particular test classes, favor implementing {@code RuntimeHintsRegistrar}
* over this API. * over this API.
* *
* <p>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 * @author Sam Brannen
* @since 6.0 * @since 6.0
* @see org.springframework.aot.hint.RuntimeHintsRegistrar * @see org.springframework.aot.hint.RuntimeHintsRegistrar

14
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 * {@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: * hints for invoking the annotated method, this implementation handles:
*
* <ul> * <ul>
* <li>Return types annotated with {@link ResponseBody}.</li> * <li>Return types annotated with {@link ResponseBody}</li>
* <li>Parameters annotated with {@link RequestBody}.</li> * <li>Parameters annotated with {@link RequestBody}</li>
* <li>{@link HttpEntity} return type and parameters.</li> * <li>{@link HttpEntity} return types and parameters</li>
* </ul> * </ul>
* *
* @author Stephane Nicoll * @author Stephane Nicoll
@ -49,6 +50,7 @@ class ControllerMappingReflectiveProcessor implements ReflectiveProcessor {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override @Override
public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
if (element instanceof Class<?> type) { if (element instanceof Class<?> type) {
@ -98,8 +100,8 @@ class ControllerMappingReflectiveProcessor implements ReflectiveProcessor {
@Nullable @Nullable
private Type getHttpEntityType(MethodParameter parameter) { private Type getHttpEntityType(MethodParameter parameter) {
MethodParameter nestedParameter = parameter.nested(); MethodParameter nestedParameter = parameter.nested();
return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ?
? null : nestedParameter.getNestedParameterType()); null : nestedParameter.getNestedParameterType());
} }
} }

1
spring-web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandlerReflectiveProcessor.java

@ -37,4 +37,5 @@ class ExceptionHandlerReflectiveProcessor extends ControllerMappingReflectivePro
} }
super.registerReturnTypeHints(hints, returnTypeParameter); super.registerReturnTypeHints(hints, returnTypeParameter);
} }
} }

3
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} * {@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 * the annotated method, this implementation handles reflection-based
* binding for return types and parameters annotated with {@link RequestBody}. * binding for return types and parameters annotated with {@link RequestBody}.
* *
@ -40,6 +40,7 @@ class HttpExchangeReflectiveProcessor implements ReflectiveProcessor {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar(); private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override @Override
public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) { public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
if (element instanceof Method method) { if (element instanceof Method method) {

Loading…
Cancel
Save