Skip to content

Regression in environment placeholder resolution in ApplicationContextRunner for 3.4.0-M3 #42720

@iparadiso

Description

@iparadiso

Problem statement

Hi Spring Team.

I'm evaluating Spring Boot 3.4.0-M3 and I ran into a regression in environment loading with tests using ApplicationContextRunner to construct programmatic application contexts and assert on their behavior.

The behavior that appears to be lost is the Environment no longer resolves environment placeholders in the following example.

Autoconfiguration to conditionally create a different implementation of an interface

@Configuration
public class AppConfiguration {

    @Bean
    public Animal testAnimal(Environment environment) {
        if (environment.getProperty("new.cat-mode.enabled", Boolean.class, false)) {
            return new Cat();
        }
        return new Dog();
    }
}

With an EnvironmentPostProcessor to conditionally load a new property source

public class PropertyEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private static final String PROPERTY_SOURCE = "classpath:/custom-properties.properties";

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        if (environment.acceptsProfiles(Profiles.of("laptop"))) {
            try {
                environment.getPropertySources()
                        .addLast(new ResourcePropertySource("custom-prop", PROPERTY_SOURCE));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

Which loads a single property with a backport placeholder property

new.cat-mode.enabled=${old.cat-mode.enabled:true}

And finally the test to validate this behavior

public class AppConfigurationTest {

    private final SpringApplication application = new SpringApplication();

    private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(AppConfiguration.class))
            .withInitializer(
                    ac -> new PropertyEnvironmentPostProcessor().postProcessEnvironment(ac.getEnvironment(), application));

    @Test
    void testCatMode() {
        contextRunner
                .withSystemProperties("spring.profiles.active=laptop",
                        "spring.application.name=apptest")
                .run(context -> {
                    assertThat(context).hasNotFailed();
                    assertThat(context).hasSingleBean(Cat.class);
                });
    }

    @Test
    void testDefaultMode() {
        contextRunner
                .run(context -> {
                    assertThat(context).hasNotFailed();
                    assertThat(context).hasSingleBean(Dog.class);
                });
    }
}

In Spring boot 3.3.x, this test passes. In 3.4.0-M3, it throws the following error with not being able to parse ${old.cat-mode.enabled:true} as a boolean.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testAnimal' defined in com.example.demo.AppConfiguration: Failed to instantiate [com.example.demo.Animal]: Factory method 'testAnimal' threw exception with message: Failed to convert from type [java.lang.String] to type [java.lang.Boolean] for value [${old.cat-mode.enabled:true}]

Expectation

The expectation is there should be no changes in environment loading and placeholder resolution in this kind of test.

Proproducing this issue

I created the following Git repo that this test setup in 3.3.x and 3.4.0-M3.

Metadata

Metadata

Assignees

No one assigned

    Labels

    for: external-projectFor an external project and not something we can fix

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions