From f0ebb057d39a770a460b345e953163fcb0b43dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicoll?= Date: Tue, 9 Dec 2025 16:42:17 +0100 Subject: [PATCH] Add missing hints for __EnvironmentPostProcessor This commit fixes the initialization of the environment in a native image by adding the necessary reflection hints so that the generated EnvironmentPostProcessor is found. Closes gh-48408 --- ...nmentPostProcessorApplicationListener.java | 8 ++++++- ...PostProcessorApplicationListenerTests.java | 22 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListener.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListener.java index 6d6554b9a0b..1a3c3a28edc 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListener.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListener.java @@ -24,7 +24,9 @@ import javax.lang.model.element.Modifier; import org.springframework.aot.AotDetector; import org.springframework.aot.generate.GeneratedClass; +import org.springframework.aot.generate.GeneratedTypeReference; import org.springframework.aot.generate.GenerationContext; +import org.springframework.aot.hint.MemberCategory; import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; @@ -59,7 +61,7 @@ import org.springframework.util.ObjectUtils; */ public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered { - private static final String AOT_FEATURE_NAME = "EnvironmentPostProcessor"; + static final String AOT_FEATURE_NAME = "EnvironmentPostProcessor"; /** * The default order for the processor. @@ -234,6 +236,10 @@ public class EnvironmentPostProcessorApplicationListener implements SmartApplica method.addParameter(SpringApplication.class, "application"); method.addCode(generateActiveProfilesInitializeCode()); }); + generationContext.getRuntimeHints() + .reflection() + .registerType(GeneratedTypeReference.of(generatedClass.getName()), + MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS); } private CodeBlock generateActiveProfilesInitializeCode() { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListenerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListenerTests.java index e40dcc9dfbc..10a90a202a8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListenerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/env/EnvironmentPostProcessorApplicationListenerTests.java @@ -35,6 +35,10 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; import org.springframework.aot.AotDetector; +import org.springframework.aot.generate.GenerationContext; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.TypeReference; +import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; import org.springframework.beans.factory.support.DefaultListableBeanFactory; @@ -209,6 +213,24 @@ class EnvironmentPostProcessorApplicationListenerTests { }); } + @Test + void aotContributionRegistersReflectionHints() { + GenericApplicationContext applicationContext = new GenericApplicationContext(); + ConfigurableEnvironment environment = new StandardEnvironment(); + environment.setActiveProfiles("one", "two"); + applicationContext.getBeanFactory().registerSingleton("environment", environment); + BeanFactoryInitializationAotContribution aotContribution = new EnvironmentBeanFactoryInitializationAotProcessor() + .processAheadOfTime(applicationContext.getBeanFactory()); + assertThat(aotContribution).isNotNull(); + GenerationContext generationContext = new TestGenerationContext(); + aotContribution.applyTo(generationContext, null); + assertThat(RuntimeHintsPredicates.reflection() + .onType(TypeReference.of(TestGenerationContext.TEST_TARGET + "__" + + EnvironmentPostProcessorApplicationListener.AOT_FEATURE_NAME)) + .withMemberCategory(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)) + .accepts(generationContext.getRuntimeHints()); + } + @Test void shouldUseAotEnvironmentPostProcessor() { SpringApplication application = new SpringApplication(ExampleAotProcessedApp.class);