Search code examples
javaspringspring-bootspring-boot-test

Spring Boot Test @ConfigurationProperties does not bind fields


Good evening everyone. I have a class that is designed for binding with properties. In the class labeled @Configuration, I make this bean object like:

// Into TargetConfiguration class

@Bean("someBeanName")
@ConfigurationProperties("some.path")
public beanProperties() {
    return new BeanProperties();
}

I would like to test all the functionality of this configuration and for this I create a test class like:

@WebFluxTest
@TestPropertySource("classpath:test.properties")
@ContextConfiguration(classes = {TargetConfiguration.class})
class Test {...}

The problem is that BeanProperties will contain null fields, but if I make some otherOtherBeanProperties and register it via @EnableConfigurationProperties inTargetConfiguration, then it will be normally filled, but for BeanProperties I can’t do this, since this bean depends on the property in test.properties. Also if I create this bean through the @TestConfiguration configuration, then it will be filled to...

Any help is appreciated.

UPD-1: The first assumption - I register some class which extends BeanDefinitionRegistryPostProcessor with @DependsOn annotation named RegistratorClass. I don't know why, but if i add @DependsOn on RegistratorClass class, my BeanProperties immediately constructed without binding (And passing to other method which want to receiver this BeanProperties). If i remove this annotation, RegistratorClass initialized the first and my BeanProperties will be normally constructed and bound to properties.


Solution

  • A BeanDefinitionRegistryPostProcessor is initialized early in the lifecycle and is intended to be used to add additional bean definitions. In the example code that you posted at https://github.com/spring-projects/spring-boot/issues/21584 you are declaring that beanGenerator depends on someOtherBeanUser. In turn, someOtherBeanUser injects beanUser. This means that someOtherBeanUser and beanUser are injected very early.

    The way configuration binding works is via the ConfigurationPropertiesBindingPostProcessor. By triggering early initialization you're forcing Spring to create beanUser before the ConfigurationPropertiesBindingPostProcessor has been registered. This means that no binding can be applied.

    A complete sample application would help determine why your properties are not being bound, but I believe that adding @EnableConfigurationProperties to TargetConfiguration or the test class itself will fix it.