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
This commit is contained in:
		
							parent
							
								
									51daeac86b
								
							
						
					
					
						commit
						549f4e7933
					
				|  | @ -112,6 +112,7 @@ public class TestContextAotGenerator { | ||||||
| 		mergedConfigMappings.forEach((mergedConfig, testClasses) -> { | 		mergedConfigMappings.forEach((mergedConfig, testClasses) -> { | ||||||
| 			logger.debug(LogMessage.format("Generating AOT artifacts for test classes %s", | 			logger.debug(LogMessage.format("Generating AOT artifacts for test classes %s", | ||||||
| 					testClasses.stream().map(Class::getName).toList())); | 					testClasses.stream().map(Class::getName).toList())); | ||||||
|  | 			registerHintsForMergedConfig(mergedConfig); | ||||||
| 			try { | 			try { | ||||||
| 				// Use first test class discovered for a given unique MergedContextConfiguration. | 				// Use first test class discovered for a given unique MergedContextConfiguration. | ||||||
| 				Class<?> testClass = testClasses.get(0); | 				Class<?> testClass = testClasses.get(0); | ||||||
|  | @ -174,8 +175,6 @@ public class TestContextAotGenerator { | ||||||
| 				Consider annotating test class [%s] with @ContextConfiguration or \ | 				Consider annotating test class [%s] with @ContextConfiguration or \ | ||||||
| 				@ContextHierarchy.""".formatted(testClass.getName())); | 				@ContextHierarchy.""".formatted(testClass.getName())); | ||||||
| 
 | 
 | ||||||
| 		registerDeclaredConstructors(contextLoader.getClass()); |  | ||||||
| 
 |  | ||||||
| 		if (contextLoader instanceof AotContextLoader aotContextLoader) { | 		if (contextLoader instanceof AotContextLoader aotContextLoader) { | ||||||
| 			try { | 			try { | ||||||
| 				ApplicationContext context = aotContextLoader.loadContextForAotProcessing(mergedConfig); | 				ApplicationContext context = aotContextLoader.loadContextForAotProcessing(mergedConfig); | ||||||
|  | @ -227,6 +226,14 @@ public class TestContextAotGenerator { | ||||||
| 				.registerType(TypeReference.of(className), MemberCategory.INVOKE_PUBLIC_METHODS); | 				.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) { | 	private void registerDeclaredConstructors(Class<?> type) { | ||||||
| 		ReflectionHints reflectionHints = this.runtimeHints.reflection(); | 		ReflectionHints reflectionHints = this.runtimeHints.reflection(); | ||||||
| 		reflectionHints.registerType(type, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); | 		reflectionHints.registerType(type, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); | ||||||
|  |  | ||||||
|  | @ -123,6 +123,7 @@ class TestContextAotGeneratorTests extends AbstractAotTests { | ||||||
| 		).forEach(type -> assertReflectionRegistered(runtimeHints, type, INVOKE_PUBLIC_CONSTRUCTORS)); | 		).forEach(type -> assertReflectionRegistered(runtimeHints, type, INVOKE_PUBLIC_CONSTRUCTORS)); | ||||||
| 
 | 
 | ||||||
| 		Set.of( | 		Set.of( | ||||||
|  | 			org.springframework.test.context.aot.samples.basic.BasicSpringTestNGTests.CustomInitializer.class, | ||||||
| 			org.springframework.test.context.support.AnnotationConfigContextLoader.class, | 			org.springframework.test.context.support.AnnotationConfigContextLoader.class, | ||||||
| 			org.springframework.test.context.support.DefaultTestContextBootstrapper.class, | 			org.springframework.test.context.support.DefaultTestContextBootstrapper.class, | ||||||
| 			org.springframework.test.context.support.DelegatingSmartContextLoader.class, | 			org.springframework.test.context.support.DelegatingSmartContextLoader.class, | ||||||
|  |  | ||||||
|  | @ -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.Autowired; | ||||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.context.ApplicationContext; | 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.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.aot.samples.common.MessageService; | ||||||
| import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; | import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; | ||||||
| 
 | 
 | ||||||
|  | @ -30,8 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat; | ||||||
|  * @author Sam Brannen |  * @author Sam Brannen | ||||||
|  * @since 6.0 |  * @since 6.0 | ||||||
|  */ |  */ | ||||||
| @ContextConfiguration(classes = BasicTestConfiguration.class) | @ContextConfiguration(classes = BasicTestConfiguration.class, initializers = CustomInitializer.class) | ||||||
| @TestPropertySource(properties = "test.engine = testng") |  | ||||||
| public class BasicSpringTestNGTests extends AbstractTestNGSpringContextTests { | public class BasicSpringTestNGTests extends AbstractTestNGSpringContextTests { | ||||||
| 
 | 
 | ||||||
| 	@Autowired | 	@Autowired | ||||||
|  | @ -51,4 +53,14 @@ public class BasicSpringTestNGTests extends AbstractTestNGSpringContextTests { | ||||||
| 			.as("@TestPropertySource").isEqualTo("testng"); | 			.as("@TestPropertySource").isEqualTo("testng"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	public static class CustomInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> { | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		public void initialize(ConfigurableApplicationContext applicationContext) { | ||||||
|  | 			applicationContext.getEnvironment().getPropertySources() | ||||||
|  | 				.addFirst(new MockPropertySource().withProperty("test.engine", "testng")); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue