Browse Source

Consider all processors when processing `@Reflective`

Previously, only the first occurance of `@Reflective` and its
processor was considered. When `@Reflective` appeared twice on a type
due to meta-annotations or inheritance, this resulted in other
processors being ignored and hints were missing as a result.

This commit updates ReflectiveRuntimeHintsRegistrar to consider
every occurance of `@Reflective` found in the type hierarchy,
and to then use the processors from each of them.

Fixes gh-29193
pull/29198/head
Andy Wilkinson 2 years ago committed by Sébastien Deleuze
parent
commit
a409e0fd2c
  1. 11
      spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java
  2. 42
      spring-core/src/test/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrarTests.java

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

@ -25,6 +25,8 @@ import java.util.List; @@ -25,6 +25,8 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.RuntimeHints;
@ -36,6 +38,7 @@ import org.springframework.util.ReflectionUtils; @@ -36,6 +38,7 @@ import org.springframework.util.ReflectionUtils;
* Process {@link Reflective} annotated elements.
*
* @author Stephane Nicoll
* @author Andy Wilkinson
* since 6.0
*/
public class ReflectiveRuntimeHintsRegistrar {
@ -89,9 +92,11 @@ public class ReflectiveRuntimeHintsRegistrar { @@ -89,9 +92,11 @@ public class ReflectiveRuntimeHintsRegistrar {
@SuppressWarnings("unchecked")
private Entry createEntry(AnnotatedElement element) {
Class<? extends ReflectiveProcessor>[] processorClasses = (Class<? extends ReflectiveProcessor>[])
MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(Reflective.class).getClassArray("value");
List<ReflectiveProcessor> processors = Arrays.stream(processorClasses).distinct()
List<Class<? extends ReflectiveProcessor>> processorClasses =
MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
.stream(Reflective.class).flatMap(annotation -> Stream.of(annotation.getClassArray("value")))
.map(type -> (Class<? extends ReflectiveProcessor>) type).collect(Collectors.toList());
List<ReflectiveProcessor> processors = processorClasses.stream().distinct()
.map(processorClass -> this.processors.computeIfAbsent(processorClass, this::instantiateClass))
.toList();
ReflectiveProcessor processorToUse = (processors.size() == 1 ? processors.get(0)

42
spring-core/src/test/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrarTests.java

@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test; @@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeHint;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.core.annotation.AliasFor;
@ -40,6 +41,7 @@ import static org.mockito.Mockito.verifyNoInteractions; @@ -40,6 +41,7 @@ import static org.mockito.Mockito.verifyNoInteractions;
* Tests for {@link ReflectiveRuntimeHintsRegistrar}.
*
* @author Stephane Nicoll
* @author Andy Wilkinson
*/
class ReflectiveRuntimeHintsRegistrarTests {
@ -61,6 +63,14 @@ class ReflectiveRuntimeHintsRegistrarTests { @@ -61,6 +63,14 @@ class ReflectiveRuntimeHintsRegistrarTests {
.isNotNull();
}
@Test
void shouldProcessWithMultipleProcessorsWithAnnotationOnType() {
process(SampleMultipleCustomProcessors.class);
TypeHint typeHint = this.runtimeHints.reflection().getTypeHint(SampleMultipleCustomProcessors.class);
assertThat(typeHint).isNotNull();
assertThat(typeHint.getMemberCategories()).containsExactly(MemberCategory.INVOKE_DECLARED_METHODS);
}
@Test
void shouldProcessAnnotationOnConstructor() {
process(SampleConstructorAnnotatedBean.class);
@ -236,6 +246,14 @@ class ReflectiveRuntimeHintsRegistrarTests { @@ -236,6 +246,14 @@ class ReflectiveRuntimeHintsRegistrarTests {
}
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective(TestTypeHintReflectiveProcessor.class)
@interface ReflectiveWithCustomProcessor {
}
interface SampleInterface {
@Reflective
@ -251,14 +269,24 @@ class ReflectiveRuntimeHintsRegistrarTests { @@ -251,14 +269,24 @@ class ReflectiveRuntimeHintsRegistrarTests {
static class SampleCustomProcessor {
@Reflective(TestReflectiveProcessor.class)
@Reflective(TestMethodHintReflectiveProcessor.class)
public String managed() {
return "test";
}
}
@Reflective
@ReflectiveWithCustomProcessor
static class SampleMultipleCustomProcessors {
public String managed() {
return "test";
}
}
private static class TestReflectiveProcessor extends SimpleReflectiveProcessor {
private static class TestMethodHintReflectiveProcessor extends SimpleReflectiveProcessor {
@Override
protected void registerMethodHint(ReflectionHints hints, Method method) {
@ -268,4 +296,14 @@ class ReflectiveRuntimeHintsRegistrarTests { @@ -268,4 +296,14 @@ class ReflectiveRuntimeHintsRegistrarTests {
}
private static class TestTypeHintReflectiveProcessor extends SimpleReflectiveProcessor {
@Override
protected void registerTypeHint(ReflectionHints hints, Class<?> type) {
super.registerTypeHint(hints, type);
hints.registerType(type, MemberCategory.INVOKE_DECLARED_METHODS);
}
}
}

Loading…
Cancel
Save