Affects: 2.5.4
Not all the properties are loaded when the bean is loaded based on the condition present in the configuration. Without the condition the values are loaded correctly.
```
@Bean
@ConditionalOnExpression("#{appProperties.approach2 eq false}")
public String approch2(AppProperties properties) {
System.out.println(properties.message); //prints null
System.out.println(properties.degree); //prints 0
return "";
}
application.properties
application.message="some message" application.degree=5 application.approach1=true application.approach2=false
---
**Comment From: snicoll**
@vvijayv the environment is prepared before the application context is refreshed. You are mentioning `application.properties` which is part of that for. To make some progress, please take the time to share a minimal sample that reproduces the problem (no code snippet in text, but an actual project we can run ourselves). You can do so by attaching a zip to this issue or sharing a link to a GitHub repository. Thank you.
**Comment From: vvijayv**
Hi @snicoll I have attached a sample project you can test this
[conditional-bug-test.zip](https://github.com/spring-projects/spring-framework/files/7568311/conditional-bug-test.zip)
**Comment From: snicoll**
Thanks. `ConditionalOnExpression` on a configuration properties bean leads to some early initialization of the bean which, somehow, means that binding does not occur at all.
**Comment From: vvijayv**
I have to make this work with this, `@ConditionalOnProperty(prefix = "appProperties", name = "approach2", havingValue = "false")`
It would be good if the lifecycle of the conditional annotations are almost same
**Comment From: wilkinsona**
I'm not sure there's anything that we can do about this in Spring Boot other than adding a warning to the javadoc of `@ConditionalOnExpression`. The SpEL expression is evaluated as part of configuration class parsing and that's out of Boot's control.
I'm a little surprised that Framework's `BeanPostProcessorChecker` doesn't log an info message stating that `appProperties` won't be eligible for post-processing. The message is missing as the condition is evaluated as part of refresh's call to `invokeBeanFactoryPostProcessors(beanFactory)`. Here's the stack of `AppProperties` being instantiated due to the SpEL expression's evaluation:
Thread [main] (Suspended (entry into method
owns: ConcurrentHashMap
owns: Object (id=51)
AppProperties.
NativeConstructorAccessorImpl.newInstance(Object[]) line: 62
DelegatingConstructorAccessorImpl.newInstance(Object[]) line: 45
Constructor
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).instantiateBean(String, RootBeanDefinition) line: 1326
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBeanInstance(String, RootBeanDefinition, Object[]) line: 1232
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).doCreateBean(String, RootBeanDefinition, Object[]) line: 582
DefaultListableBeanFactory(AbstractAutowireCapableBeanFactory).createBean(String, RootBeanDefinition, Object[]) line: 542
DefaultListableBeanFactory(AbstractBeanFactory).lambda$doGetBean$0(String, RootBeanDefinition, Object[]) line: 335
1278839936.getObject() line: not available
DefaultListableBeanFactory(DefaultSingletonBeanRegistry).getSingleton(String, ObjectFactory<?>) line: 234
DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class
DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 208
BeanFactoryResolver.resolve(EvaluationContext, String) line: 51
BeanReference.getValueInternal(ExpressionState) line: 55
CompoundExpression.getValueRef(ExpressionState) line: 55
CompoundExpression.getValueInternal(ExpressionState) line: 91
OpEQ.getValueInternal(ExpressionState) line: 42
OpEQ.getValueInternal(ExpressionState) line: 32
OpEQ(SpelNodeImpl).getValue(ExpressionState) line: 112
SpelExpression.getValue(EvaluationContext) line: 272
StandardBeanExpressionResolver.evaluate(String, BeanExpressionContext) line: 167
OnExpressionCondition.evaluateExpression(ConfigurableListableBeanFactory, String) line: 60
OnExpressionCondition.getMatchOutcome(ConditionContext, AnnotatedTypeMetadata) line: 48
OnExpressionCondition(SpringBootCondition).matches(ConditionContext, AnnotatedTypeMetadata) line: 47
ConditionEvaluator.shouldSkip(AnnotatedTypeMetadata, ConfigurationCondition$ConfigurationPhase) line: 108
ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(BeanMethod) line: 193
ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClass, ConfigurationClassBeanDefinitionReader$TrackedConditionEvaluator) line: 153
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set
ConfigurationClassPostProcessor.processConfigBeanDefinitions(BeanDefinitionRegistry) line: 343
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry) line: 247
PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(Collection
AnnotationConfigApplicationContext(AbstractApplicationContext).invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory) line: 746
AnnotationConfigApplicationContext(AbstractApplicationContext).refresh() line: 564
SpringApplication.refresh(ConfigurableApplicationContext) line: 765
SpringApplication.refreshContext(ConfigurableApplicationContext) line: 445
SpringApplication.run(String...) line: 338
SpringApplication.run(Class<?>[], String[]) line: 1354
SpringApplication.run(Class<?>, String...) line: 1343
ConditionalBugTestApplication.main(String[]) line: 14
```
The checker isn't registered until the next line in refresh()
where registerBeanPostProcessors(beanFactory)
is called. It's also at this point that the post-processor for configuration property binding would be registered which explains why the properties are not bound when the SpEL expression evaluation triggers early initialisation of the bean.
I wonder if the registration of BeanPostProcessorChecker
could be brought forward so that it happens before configuration class parsing?
Comment From: jhoeller
Bringing BeanPostProcessorChecker
forward would mean bringing the BeanPostProcessor
bean type retrieval forward, and that's a tough pill to swallow. From that perspective, I don't see us improving the warning situation here; we'll have to rely on documentation.