From 549f4e7933edbaca737e0b18472c8fe4530e054a Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 2 Sep 2022 14:17:43 +0200 Subject: [PATCH] Register runtime hints for ApplicationContextInitializers in the TCF This commit introduces automatic registration of runtime hints for ApplicationContextInitializers configured via the `initializers` attribute in @ContextConfiguration. See gh-29021 --- .../context/aot/TestContextAotGenerator.java | 11 +++++++++-- .../aot/TestContextAotGeneratorTests.java | 1 + .../samples/basic/BasicSpringTestNGTests.java | 18 +++++++++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) 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 b53cca2ff4c..516bdd80bfb 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 @@ -112,6 +112,7 @@ public class TestContextAotGenerator { mergedConfigMappings.forEach((mergedConfig, testClasses) -> { logger.debug(LogMessage.format("Generating AOT artifacts for test classes %s", testClasses.stream().map(Class::getName).toList())); + registerHintsForMergedConfig(mergedConfig); try { // Use first test class discovered for a given unique MergedContextConfiguration. Class testClass = testClasses.get(0); @@ -174,8 +175,6 @@ public class TestContextAotGenerator { Consider annotating test class [%s] with @ContextConfiguration or \ @ContextHierarchy.""".formatted(testClass.getName())); - registerDeclaredConstructors(contextLoader.getClass()); - if (contextLoader instanceof AotContextLoader aotContextLoader) { try { ApplicationContext context = aotContextLoader.loadContextForAotProcessing(mergedConfig); @@ -227,6 +226,14 @@ public class TestContextAotGenerator { .registerType(TypeReference.of(className), MemberCategory.INVOKE_PUBLIC_METHODS); } + private void registerHintsForMergedConfig(MergedContextConfiguration mergedConfig) { + ContextLoader contextLoader = mergedConfig.getContextLoader(); + if (contextLoader != null) { + registerDeclaredConstructors(contextLoader.getClass()); + } + mergedConfig.getContextInitializerClasses().forEach(this::registerDeclaredConstructors); + } + private void registerDeclaredConstructors(Class type) { ReflectionHints reflectionHints = this.runtimeHints.reflection(); reflectionHints.registerType(type, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java index 7ddf70477e6..5d2be837872 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/TestContextAotGeneratorTests.java @@ -123,6 +123,7 @@ class TestContextAotGeneratorTests extends AbstractAotTests { ).forEach(type -> assertReflectionRegistered(runtimeHints, type, INVOKE_PUBLIC_CONSTRUCTORS)); Set.of( + org.springframework.test.context.aot.samples.basic.BasicSpringTestNGTests.CustomInitializer.class, org.springframework.test.context.support.AnnotationConfigContextLoader.class, org.springframework.test.context.support.DefaultTestContextBootstrapper.class, org.springframework.test.context.support.DelegatingSmartContextLoader.class, diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringTestNGTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringTestNGTests.java index d0163f82da1..c59e3ec51cf 100644 --- a/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringTestNGTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/aot/samples/basic/BasicSpringTestNGTests.java @@ -19,8 +19,11 @@ package org.springframework.test.context.aot.samples.basic; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.mock.env.MockPropertySource; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.aot.samples.basic.BasicSpringTestNGTests.CustomInitializer; import org.springframework.test.context.aot.samples.common.MessageService; import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; @@ -30,8 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Sam Brannen * @since 6.0 */ -@ContextConfiguration(classes = BasicTestConfiguration.class) -@TestPropertySource(properties = "test.engine = testng") +@ContextConfiguration(classes = BasicTestConfiguration.class, initializers = CustomInitializer.class) public class BasicSpringTestNGTests extends AbstractTestNGSpringContextTests { @Autowired @@ -51,4 +53,14 @@ public class BasicSpringTestNGTests extends AbstractTestNGSpringContextTests { .as("@TestPropertySource").isEqualTo("testng"); } + public static class CustomInitializer implements ApplicationContextInitializer { + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + applicationContext.getEnvironment().getPropertySources() + .addFirst(new MockPropertySource().withProperty("test.engine", "testng")); + } + + } + }