'Combine @Component and @ConditionalOnBean into one annotation
I want to combine two Spring
annotations into a single one.
More exactly I want to combine @Component
and @ConditionalOnBean
into one annotation named @SubComponent
.
Is this possible?
What I have tried so far:
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Configuration
@ConditionalOnProperty(prefix = "user", name = "property", havingValue = "true")
@Slf4j
static class TestableConfiguration {
public TestableConfiguration() {
log.info(getClass().getSimpleName() + " 666666 initialized");
}
@Component
@ConditionalOnBean(TestableConfiguration.class)
// @SubComponent(TestableConfiguration.class)
static class Insight {
public Insight() {
log.info(getClass().getSimpleName() + " 666666 initialized");
}
}
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@ConditionalOnBean
@interface SubComponent {
@AliasFor(attribute = "value", annotation = ConditionalOnBean.class)
Class<?>[] value() default {};
}
but I am receiving an exception :
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: file [C:\Users\QV29YT\work\work_testing\2022_apr_27\demo\target\classes\com\example\demo\SubComponent.class]; nested exception is java.lang.IllegalStateException: Error processing condition on com.example.demo.SubComponent
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.scanCandidateComponents(ClassPathScanningCandidateComponentProvider.java:457) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:316) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:276) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:128) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:296) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:207) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:175) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[spring-boot-2.6.7.jar:2.6.7]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.7.jar:2.6.7]
at com.example.demo.DemoApplication.main(DemoApplication.java:18) ~[classes/:na]
Caused by: java.lang.IllegalStateException: Error processing condition on com.example.demo.SubComponent
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:60) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:90) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:71) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.isConditionMatch(ClassPathScanningCandidateComponentProvider.java:512) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.isCandidateComponent(ClassPathScanningCandidateComponentProvider.java:495) ~[spring-context-5.3.19.jar:5.3.19]
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.scanCandidateComponents(ClassPathScanningCandidateComponentProvider.java:430) ~[spring-context-5.3.19.jar:5.3.19]
... 20 common frames omitted
Caused by: java.lang.IllegalStateException: @ConditionalOnBean did not specify a bean using type, name or annotation
at org.springframework.boot.autoconfigure.condition.OnBeanCondition$Spec.validate(OnBeanCondition.java:492) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.boot.autoconfigure.condition.OnBeanCondition$Spec.<init>(OnBeanCondition.java:443) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:118) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47) ~[spring-boot-autoconfigure-2.6.7.jar:2.6.7]
... 26 common frames omitted
Process finished with exit code 1
What I want to do is have something as the line commented, to create a bean if certain condition is meet.
Do you know if this is possible?
Or are there any other ways of handling this?
Edited after Alex's response:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@ConditionalOnBean(value = Object.class) // updated this
@interface SubComponent {
@AliasFor(attribute = "value", annotation = ConditionalOnBean.class)
Class<?>[] value() default {};
}
It seems that somehow Spring
does a pre-verification if all things are in order.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|