0

I got two defined components

Class A

package a;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class A extends OncePerRequestFilter {

Class B

package b;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@Primary
class A extends a.A {

Using this two components in my Spring (boot 4.2.5) application, I am getting following error:

... 
nested exception is org.springframework.context.annotation.
ConflictingBeanDefinitionException:
Annotation-specified bean name 'a' for bean class [a.A] conflicts with existing, 
non-compatible bean definition of same name and class [b.A]

I would have expected (and am wanting to), that b.A would be used in favor of a.A as replacement / be overriden.

Why am I getting this error message here? How can use b.A as "Component a"?

Full exception / sprint-boot startup error:

Application startup failed","stack_trace":"o.s.c.a.ConflictingBeanDefinitionException: 
Annotation-specified bean name 'httpAccessLogFilter' for bean class [b.A] conflicts with existing, 
non-compatible bean definition of same name and class [a.A]
at o.s.c.a.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:320)
at o.s.c.a.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:259)
at o.s.c.a.ComponentScanAnnotationParser.parse(ComponentScanAnnotationParser.java:137)
at o.s.c.a.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:268)
at o.s.c.a.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:232)
at o.s.c.a.ConfigurationClassParser.parse(ConfigurationClassParser.java:199)
at o.s.c.a.ConfigurationClassParser.parse(ConfigurationClassParser.java:168)
... 16 common frames omitted
Wrapped by: o.s.b.f.BeanDefinitionStoreException: Failed to parse configuration class [a.SpringBootApplication]; 
nested exception is org.springframework.context.annotation.ConflictingBeanDefinitionException: A
nnotation-specified bean name 'a' for bean class [b.A] conflicts with existing, non-compatible bean definition of same name and class [a.A]
at o.s.c.a.ConfigurationClassParser.parse(ConfigurationClassParser.java:182)
at o.s.c.a.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:321)
at o.s.c.a.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243)
at o.s.c.s.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273)
at o.s.c.s.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98)
at o.s.c.s.AbstractApplicationContext.invokeBeanFactoryPostProcessors(Abst...
Markus Schulte
  • 4,171
  • 3
  • 47
  • 58

1 Answers1

1

Seems as if same beans from different packages are not supported.

"considers them as compatible when the existing bean definition comes from the same source or from a non-scanning source." ClassPathBeanDefinitionScanner:isCompatible

At Spring, this is yet discussed in their Issue-Tracker, see SPR-14665 and SPR-10808.

I got an ugly workaround. The ancestor gets a different name, and is annotated "ConditionalOnMissingBean".

Ancestor:

package a;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnMissingBean(name = "a")
class AncestorOfA extends OncePerRequestFilter {

Class B:

package b;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
class A extends a.AncestorOfA {

This way, I have component "ancestorOfA", if I do not wish to implement an own one. If I wish to use an own version, I will have component "a", but not "ancestorOfA".

Obvious disadvantage is, the child-component has be be named correctly.

Markus Schulte
  • 4,171
  • 3
  • 47
  • 58