From 4556895e6e97931c642e30c8c874b690708f2ea1 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 17 Aug 2022 14:23:11 +0200 Subject: [PATCH] Expose registrar for @Reflective This commit exposes the logic of processing `@Reflective` on beans so that it can be reused in custom arrangements. Closes gh-28975 --- ...BeanFactoryInitializationAotProcessor.java | 68 +++++++++++ .../resources/META-INF/spring/aot.factories | 4 +- ...actoryInitializationAotProcessorTests.java | 107 ++++++++++++++++++ .../aot/hint/annotation/Reflective.java | 1 + .../ReflectiveRuntimeHintsRegistrar.java | 101 +++++++---------- .../ReflectiveRuntimeHintsRegistrarTests.java | 56 ++++----- 6 files changed, 242 insertions(+), 95 deletions(-) create mode 100644 spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessor.java create mode 100644 spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessorTests.java rename spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java => spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java (57%) rename spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java => spring-core/src/test/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrarTests.java (67%) diff --git a/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessor.java b/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessor.java new file mode 100644 index 000000000000..238350ffc226 --- /dev/null +++ b/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessor.java @@ -0,0 +1,68 @@ +/* + * 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.context.aot; + +import java.util.Arrays; + +import org.springframework.aot.generate.GenerationContext; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.annotation.Reflective; +import org.springframework.aot.hint.annotation.ReflectiveProcessor; +import org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.RegisteredBean; + +/** + * AOT {@code BeanFactoryInitializationAotProcessor} that detects the presence + * of {@link Reflective @Reflective} on annotated elements of all registered + * beans and invokes the underlying {@link ReflectiveProcessor} implementations. + * + * @author Stephane Nicoll + * @author Sebastien Deleuze + */ +class ReflectiveProcessorBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor { + + private static final ReflectiveRuntimeHintsRegistrar REGISTRAR = new ReflectiveRuntimeHintsRegistrar(); + + @Override + public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableListableBeanFactory beanFactory) { + Class[] beanTypes = Arrays.stream(beanFactory.getBeanDefinitionNames()) + .map(beanName -> RegisteredBean.of(beanFactory, beanName).getBeanClass()) + .toArray(Class[]::new); + return new ReflectiveProcessorBeanFactoryInitializationAotContribution(beanTypes); + } + + private static class ReflectiveProcessorBeanFactoryInitializationAotContribution implements BeanFactoryInitializationAotContribution { + + private final Class[] types; + + public ReflectiveProcessorBeanFactoryInitializationAotContribution(Class[] types) { + this.types = types; + } + + @Override + public void applyTo(GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) { + RuntimeHints runtimeHints = generationContext.getRuntimeHints(); + REGISTRAR.registerRuntimeHints(runtimeHints, this.types); + } + + } + +} diff --git a/spring-context/src/main/resources/META-INF/spring/aot.factories b/spring-context/src/main/resources/META-INF/spring/aot.factories index 8b49207ec26c..e6f0e9cb772e 100644 --- a/spring-context/src/main/resources/META-INF/spring/aot.factories +++ b/spring-context/src/main/resources/META-INF/spring/aot.factories @@ -1,3 +1,5 @@ +org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor= \ +org.springframework.context.aot.ReflectiveProcessorBeanFactoryInitializationAotProcessor + org.springframework.beans.factory.aot.BeanRegistrationAotProcessor= \ -org.springframework.context.aot.ReflectiveProcessorBeanRegistrationAotProcessor,\ org.springframework.cache.annotation.CachingBeanRegistrationAotProcessor diff --git a/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessorTests.java b/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessorTests.java new file mode 100644 index 000000000000..cf0cf03d8495 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanFactoryInitializationAotProcessorTests.java @@ -0,0 +1,107 @@ +/* + * 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.context.aot; + +import java.lang.reflect.Constructor; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.generate.GenerationContext; +import org.springframework.aot.hint.annotation.Reflective; +import org.springframework.aot.hint.predicate.ReflectionHintsPredicates; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; +import org.springframework.beans.factory.aot.AotServices; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; +import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; +import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.core.testfixture.aot.generate.TestGenerationContext; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link ReflectiveProcessorBeanFactoryInitializationAotProcessor}. + * + * @author Stephane Nicoll + * @author Sebastien Deleuze + */ +class ReflectiveProcessorBeanFactoryInitializationAotProcessorTests { + + private final ReflectiveProcessorBeanFactoryInitializationAotProcessor processor = new ReflectiveProcessorBeanFactoryInitializationAotProcessor(); + + private final GenerationContext generationContext = new TestGenerationContext(); + + @Test + void processorIsRegistered() { + assertThat(AotServices.factories(getClass().getClassLoader()).load(BeanFactoryInitializationAotProcessor.class)) + .anyMatch(ReflectiveProcessorBeanFactoryInitializationAotProcessor.class::isInstance); + } + + @Test + void shouldProcessAnnotationOnType() { + process(SampleTypeAnnotatedBean.class); + assertThat(RuntimeHintsPredicates.reflection().onType(SampleTypeAnnotatedBean.class)) + .accepts(this.generationContext.getRuntimeHints()); + } + + @Test + void shouldProcessAllBeans() throws NoSuchMethodException { + ReflectionHintsPredicates reflection = RuntimeHintsPredicates.reflection(); + process(SampleTypeAnnotatedBean.class, SampleConstructorAnnotatedBean.class); + Constructor constructor = SampleConstructorAnnotatedBean.class.getDeclaredConstructor(String.class); + assertThat(reflection.onType(SampleTypeAnnotatedBean.class).and(reflection.onConstructor(constructor))) + .accepts(this.generationContext.getRuntimeHints()); + } + + private void process(Class... beanClasses) { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + for (Class beanClass : beanClasses) { + beanFactory.registerBeanDefinition(beanClass.getName(), new RootBeanDefinition(beanClass)); + } + BeanFactoryInitializationAotContribution contribution = this.processor.processAheadOfTime(beanFactory); + assertThat(contribution).isNotNull(); + contribution.applyTo(this.generationContext, mock(BeanFactoryInitializationCode.class)); + } + + @Reflective + @SuppressWarnings("unused") + static class SampleTypeAnnotatedBean { + + private String notManaged; + + public void notManaged() { + + } + } + + @SuppressWarnings("unused") + static class SampleConstructorAnnotatedBean { + + @Reflective + SampleConstructorAnnotatedBean(String name) { + + } + + SampleConstructorAnnotatedBean(Integer nameAsNumber) { + + } + + } + +} 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 0dba252455e9..ef6219b3b55b 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 @@ -39,6 +39,7 @@ * @author Sam Brannen * @since 6.0 * @see SimpleReflectiveProcessor + * @see ReflectiveRuntimeHintsRegistrar */ @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD }) diff --git a/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java b/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java similarity index 57% rename from spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java rename to spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java index 7080bcfb0cbb..88febd090591 100644 --- a/spring-context/src/main/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessor.java +++ b/spring-core/src/main/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrar.java @@ -14,60 +14,65 @@ * limitations under the License. */ -package org.springframework.context.aot; +package org.springframework.aot.hint.annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.HashMap; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.hint.ReflectionHints; import org.springframework.aot.hint.RuntimeHints; -import org.springframework.aot.hint.annotation.Reflective; -import org.springframework.aot.hint.annotation.ReflectiveProcessor; import org.springframework.aot.hint.support.RuntimeHintsUtils; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; -import org.springframework.beans.factory.aot.BeanRegistrationAotProcessor; -import org.springframework.beans.factory.aot.BeanRegistrationCode; -import org.springframework.beans.factory.support.RegisteredBean; import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.MergedAnnotations; -import org.springframework.lang.Nullable; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; /** - * AOT {@code BeanRegistrationAotProcessor} that detects the presence of - * {@link Reflective @Reflective} on annotated elements and invokes the - * underlying {@link ReflectiveProcessor} implementations. + * Process {@link Reflective} annotated elements. * * @author Stephane Nicoll - * @author Sebastien Deleuze + * since 6.0 */ -class ReflectiveProcessorBeanRegistrationAotProcessor implements BeanRegistrationAotProcessor { +public class ReflectiveRuntimeHintsRegistrar { private final Map, ReflectiveProcessor> processors = new HashMap<>(); - @Nullable - @Override - public BeanRegistrationAotContribution processAheadOfTime(RegisteredBean registeredBean) { - Class beanClass = registeredBean.getBeanClass(); - Set entries = new LinkedHashSet<>(); - processType(entries, beanClass); - for (Class implementedInterface : ClassUtils.getAllInterfacesForClass(beanClass)) { - processType(entries, implementedInterface); - } - if (!entries.isEmpty()) { - return new ReflectiveProcessorBeanRegistrationAotContribution(entries); + + /** + * Register the relevant runtime hints for elements that are annotated with + * {@link Reflective}. + * @param runtimeHints the runtime hints instance to use + * @param types the types to process + */ + public void registerRuntimeHints(RuntimeHints runtimeHints, Class... types) { + Set entries = new HashSet<>(); + Arrays.stream(types).forEach(type -> { + processType(entries, type); + for (Class implementedInterface : ClassUtils.getAllInterfacesForClass(type)) { + processType(entries, implementedInterface); + } + }); + entries.forEach(entry -> { + AnnotatedElement element = entry.element(); + entry.processor().registerReflectionHints(runtimeHints.reflection(), element); + registerAnnotationIfNecessary(runtimeHints, element); + }); + } + + private void registerAnnotationIfNecessary(RuntimeHints hints, AnnotatedElement element) { + MergedAnnotation reflectiveAnnotation = MergedAnnotations.from(element) + .get(Reflective.class); + MergedAnnotation metaSource = reflectiveAnnotation.getMetaSource(); + if (metaSource != null) { + RuntimeHintsUtils.registerAnnotationIfNecessary(hints, metaSource); } - return null; } private void processType(Set entries, Class typeToProcess) { @@ -99,13 +104,22 @@ private Entry createEntry(AnnotatedElement element) { Class[] processorClasses = (Class[]) MergedAnnotations.from(element, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY).get(Reflective.class).getClassArray("value"); List processors = Arrays.stream(processorClasses).distinct() - .map(processorClass -> this.processors.computeIfAbsent(processorClass, BeanUtils::instantiateClass)) + .map(processorClass -> this.processors.computeIfAbsent(processorClass, this::instantiateClass)) .toList(); ReflectiveProcessor processorToUse = (processors.size() == 1 ? processors.get(0) : new DelegateReflectiveProcessor(processors)); return new Entry(element, processorToUse); } + private ReflectiveProcessor instantiateClass(Class type) { + try { + return type.getDeclaredConstructor().newInstance(); + } + catch (Exception ex) { + throw new IllegalStateException("Failed to instantiate " + type, ex); + } + } + static class DelegateReflectiveProcessor implements ReflectiveProcessor { private final Iterable processors; @@ -123,33 +137,4 @@ public void registerReflectionHints(ReflectionHints hints, AnnotatedElement elem private record Entry(AnnotatedElement element, ReflectiveProcessor processor) {} - private static class ReflectiveProcessorBeanRegistrationAotContribution implements BeanRegistrationAotContribution { - - private final Iterable entries; - - public ReflectiveProcessorBeanRegistrationAotContribution(Iterable entries) { - this.entries = entries; - } - - @Override - public void applyTo(GenerationContext generationContext, BeanRegistrationCode beanRegistrationCode) { - RuntimeHints runtimeHints = generationContext.getRuntimeHints(); - this.entries.forEach(entry -> { - AnnotatedElement element = entry.element(); - entry.processor().registerReflectionHints(runtimeHints.reflection(), element); - registerAnnotationIfNecessary(runtimeHints, element); - }); - } - - private void registerAnnotationIfNecessary(RuntimeHints hints, AnnotatedElement element) { - 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/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java b/spring-core/src/test/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrarTests.java similarity index 67% rename from spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java rename to spring-core/src/test/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrarTests.java index cf502e011752..fc00dfa04e13 100644 --- a/spring-context/src/test/java/org/springframework/context/aot/ReflectiveProcessorBeanRegistrationAotProcessorTests.java +++ b/spring-core/src/test/java/org/springframework/aot/hint/annotation/ReflectiveRuntimeHintsRegistrarTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.context.aot; +package org.springframework.aot.hint.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -24,52 +24,45 @@ import org.junit.jupiter.api.Test; -import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.TypeReference; -import org.springframework.aot.hint.annotation.Reflective; import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; -import org.springframework.beans.factory.aot.BeanRegistrationAotContribution; -import org.springframework.beans.factory.aot.BeanRegistrationCode; -import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.beans.factory.support.RegisteredBean; -import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.SynthesizedAnnotation; -import org.springframework.core.testfixture.aot.generate.TestGenerationContext; -import org.springframework.lang.Nullable; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyNoInteractions; /** - * Tests for {@link ReflectiveProcessorBeanRegistrationAotProcessor}. + * Tests for {@link ReflectiveRuntimeHintsRegistrar}. * * @author Stephane Nicoll - * @author Sebastien Deleuze */ -class ReflectiveProcessorBeanRegistrationAotProcessorTests { +class ReflectiveRuntimeHintsRegistrarTests { - private final ReflectiveProcessorBeanRegistrationAotProcessor processor = new ReflectiveProcessorBeanRegistrationAotProcessor(); + private final ReflectiveRuntimeHintsRegistrar registrar = new ReflectiveRuntimeHintsRegistrar(); - private final GenerationContext generationContext = new TestGenerationContext(); + private final RuntimeHints runtimeHints = new RuntimeHints(); @Test void shouldIgnoreNonAnnotatedType() { - assertThat(createContribution(String.class)).isNull(); + RuntimeHints mock = mock(RuntimeHints.class); + this.registrar.registerRuntimeHints(mock, String.class); + verifyNoInteractions(mock); } @Test void shouldProcessAnnotationOnType() { process(SampleTypeAnnotatedBean.class); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleTypeAnnotatedBean.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleTypeAnnotatedBean.class)) .isNotNull(); } @Test void shouldProcessAnnotationOnConstructor() { process(SampleConstructorAnnotatedBean.class); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleConstructorAnnotatedBean.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleConstructorAnnotatedBean.class)) .satisfies(typeHint -> assertThat(typeHint.constructors()).singleElement() .satisfies(constructorHint -> assertThat(constructorHint.getParameterTypes()) .containsExactly(TypeReference.of(String.class)))); @@ -78,7 +71,7 @@ void shouldProcessAnnotationOnConstructor() { @Test void shouldProcessAnnotationOnField() { process(SampleFieldAnnotatedBean.class); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleFieldAnnotatedBean.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleFieldAnnotatedBean.class)) .satisfies(typeHint -> assertThat(typeHint.fields()).singleElement() .satisfies(fieldHint -> assertThat(fieldHint.getName()).isEqualTo("managed"))); } @@ -86,7 +79,7 @@ void shouldProcessAnnotationOnField() { @Test void shouldProcessAnnotationOnMethod() { process(SampleMethodAnnotatedBean.class); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleMethodAnnotatedBean.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleMethodAnnotatedBean.class)) .satisfies(typeHint -> assertThat(typeHint.methods()).singleElement() .satisfies(methodHint -> assertThat(methodHint.getName()).isEqualTo("managed"))); } @@ -94,14 +87,14 @@ void shouldProcessAnnotationOnMethod() { @Test void shouldNotRegisterAnnotationProxyIfNotNeeded() { process(SampleMethodMetaAnnotatedBean.class); - RuntimeHints runtimeHints = this.generationContext.getRuntimeHints(); + RuntimeHints runtimeHints = this.runtimeHints; assertThat(runtimeHints.proxies().jdkProxies()).isEmpty(); } @Test void shouldRegisterAnnotationProxy() { process(SampleMethodMetaAnnotatedBeanWithAlias.class); - RuntimeHints runtimeHints = this.generationContext.getRuntimeHints(); + RuntimeHints runtimeHints = this.runtimeHints; assertThat(RuntimeHintsPredicates.proxies().forInterfaces( SampleInvoker.class, SynthesizedAnnotation.class)).accepts(runtimeHints); } @@ -109,10 +102,10 @@ void shouldRegisterAnnotationProxy() { @Test void shouldProcessAnnotationOnInterface() { process(SampleMethodAnnotatedBeanWithInterface.class); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleInterface.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleInterface.class)) .satisfies(typeHint -> assertThat(typeHint.methods()).singleElement() .satisfies(methodHint -> assertThat(methodHint.getName()).isEqualTo("managed"))); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleMethodAnnotatedBeanWithInterface.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleMethodAnnotatedBeanWithInterface.class)) .satisfies(typeHint -> assertThat(typeHint.methods()).singleElement() .satisfies(methodHint -> assertThat(methodHint.getName()).isEqualTo("managed"))); } @@ -120,25 +113,16 @@ void shouldProcessAnnotationOnInterface() { @Test void shouldProcessAnnotationOnInheritedClass() { process(SampleMethodAnnotatedBeanWithInheritance.class); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleInheritedClass.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleInheritedClass.class)) .satisfies(typeHint -> assertThat(typeHint.methods()).singleElement() .satisfies(methodHint -> assertThat(methodHint.getName()).isEqualTo("managed"))); - assertThat(this.generationContext.getRuntimeHints().reflection().getTypeHint(SampleMethodAnnotatedBeanWithInheritance.class)) + assertThat(this.runtimeHints.reflection().getTypeHint(SampleMethodAnnotatedBeanWithInheritance.class)) .satisfies(typeHint -> assertThat(typeHint.methods()).singleElement() .satisfies(methodHint -> assertThat(methodHint.getName()).isEqualTo("managed"))); } - @Nullable - private BeanRegistrationAotContribution createContribution(Class beanClass) { - DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); - beanFactory.registerBeanDefinition(beanClass.getName(), new RootBeanDefinition(beanClass)); - return this.processor.processAheadOfTime(RegisteredBean.of(beanFactory, beanClass.getName())); - } - private void process(Class beanClass) { - BeanRegistrationAotContribution contribution = createContribution(beanClass); - assertThat(contribution).isNotNull(); - contribution.applyTo(this.generationContext, mock(BeanRegistrationCode.class)); + this.registrar.registerRuntimeHints(this.runtimeHints, beanClass); } @Reflective