I'm trying to use the @ConfigurationCondition
annotation to register a bean based on a dynamic condition. This dynamic condition is present in another bean.
Putting the code below to better describe this :
Below the class ImplementationA.java
which I want to instantiate only if a certain condition is true. I've used the @Conditional
annotation here on this class to achieve this.
@Component
@Conditional(MyConfigurationCondition.class)
public class ImplementationA{
@Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
Below is the MyConfigurationCondition.java
which has been passed to the @Conditional
annotation in the above ImplementationA.java
.
public class MyConfigurationCondition implements ConfigurationCondition {
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
MyConfig myConfig = (MyConfig)context.getBeanFactory().getBean(MyConfig.class);
if(myConfig.getCustomFlag()){
return true;
}
return false;
}
}
Notice in the above code, we are returning true using a function(getCustomFlag()
) of the bean MyConfig.class
. And we are trying to get this bean from the applicationContext
(this is the reason I've returned ConfigurationPhase.REGISTER_BEAN
from the overridden getConfigurationPhase
method)
Below the code for the MyConfig.class
@Component
public class MyConfig {
private final Component1 component1;
private final Component2 component2;
@Autowired
public MyConfig(Component1 component1, Component2 component2) {
System.out.println("Inside MyConfig(Component1,Component2)");
this.component1 = component1;
this.component2 = component2;
}
public getCustomFlag(){
return component1.flag() && component2.flag();
}
}
But when I run the Spring Boot application, I get this exception:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myConfig' defined in file [com.config.MyConfig.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.config.MyConfig]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.config.MyConfig.<init>()
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1232)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:233)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1282)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1243)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:494)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:349)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:342)
at com.service.condition.MyConfigurationCondition.matches(MyConfigurationCondition.java:37)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$TrackedConditionEvaluator.shouldSkip(ConfigurationClassBeanDefinitionReader.java:489)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:140)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:129)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:343)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564)
at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295)
at com.sagnik.ReactiveWebApplication.ReactiveWebApplication.main(ReactiveWebApplication.java:16)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.config.MyConfig]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.config.MyConfig.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:83)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1326)
... 30 more
Caused by: java.lang.NoSuchMethodException: com.config.MyConfig.<init>()
at java.base/java.lang.Class.getConstructor0(Class.java:3585)
at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2754)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:78)
... 31 more
I can understand from the exception that inside the matches
method of MyConfigurationCondition.java
, when spring encounters the line MyConfig myConfig = (MyConfig)context.getBeanFactory().getBean(MyConfig.class);
, it tries to instantiate MyConfig.java
with the default constructor which is ofcourse not available in the class definition. My question is why is Spring trying to instantiate it manually using the default constructor when this bean should be available by default(instantiate using Autowired constructor) once the component scanning is completed.
Any help would be hugely appreciated.