Any bean that is @ConfigurationPropertiesBinding
will be created during bean post-processing for configuration property binding. As such, it may not be eligible for full post-processing which will result in a warning being logged. The warning will be something like this:
2025-05-20T15:19:49.363+01:00 WARN 26216 --- [gh-45618] [ main] trationDelegate$BeanPostProcessorChecker : Bean 'stringOrNumberMigrationVersionConverter' of type [org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration$StringOrNumberToMigrationVersionConverter] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). Is this bean getting eagerly injected/applied to a currently created BeanPostProcessor [methodValidationPostProcessor]? Check the corresponding BeanPostProcessor declaration and its dependencies/advisors. If this bean does not have to be post-processed, declare it with ROLE_INFRASTRUCTURE.
As the warning suggests, it can be avoided by declaring the bean in the infrastructure role (as well as declaring the bean method static
(#45621)). I think we should meta-annotate @ConfigurationPropertiesBinding
with @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
but I'd like to discuss this with the team to make sure I haven't overlooked anything and to agree upon the branches that will have the fix applied.
Comment From: wilkinsona
We discussed this today and decided that the recommendation to use static
is sufficient.
Comment From: nosan
I am not sure that the static
modifier alone is sufficient, at least the following test shows otherwise:
@ExtendWith(OutputCaptureExtension.class)
class ConfigurationPropertiesBindingTests {
@Test
void infracheck(CapturedOutput capturedOutput) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(InfraBeanPostProcessorConfiguration.class, InfraConfig.class);
context.refresh();
context.close();
assertThat(capturedOutput.getAll()).doesNotContain("is not eligible for getting processed");
}
@ConfigurationProperties("infra")
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static class InfraProperties {
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(InfraProperties.class)
static class InfraConfig {
@Bean
@ConfigurationPropertiesBinding
static Converter<Object, Object> infraConverter() {
return (source) -> source;
}
}
@Configuration(proxyBeanMethods = false)
static class InfraBeanPostProcessorConfiguration {
@Bean
static InfraBeanPostProcessor infraBeanPostProcessor(InfraProperties infraProperties) {
return new InfraBeanPostProcessor();
}
}
static class InfraBeanPostProcessor implements BeanPostProcessor {
}
}
When @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
is used together with @ConfigurationPropertiesBinding
on the converter's @Bean
method, the warning is no longer logged.
Comment From: wilkinsona
Yes, that's right. However, our opinion is that the better fix is not to inject dependencies into a method that defines a BeanPostProcessor
. The static
just prevents InfraBeanPostProcessorConfiguration
from also being affected.
Comment From: nosan
I understand this, but since @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
can be used on @ConfigurationProperties
, users might expect
that they can inject it into a BeanPostProcessor
(which is a valid use case). However, they cannot, due to @ConfigurationPropertiesBinding
.
I think this is exactly what happened in https://github.com/spring-projects/spring-boot/issues/45618. Everyone expected it to work, but it did not.
If, for some reason, someone tries to do the same in the future, they will probably face the same issue because of a similar cause, and users can't change FlywayAutoConfiguration
or something else in the Spring Boot codebase to avoid this issue.