Search code examples
javaspringinversion-of-controlautowired

How do I extend a named Spring bean when using a @Qualifier specified bean injection point?


How do I extend a named bean when using a @Qualifier specified bean injection point?

I have project 1 consisting of 3 beans:

@Component("bean1")
public class Bean1 implements Bean {
}

@Component("bean2")
public class Bean2 implements Bean {
}

@Component("bean3")
public class Bean3 {
    private Bean bean;

    public void setBean(@Qualifier("bean1") final Bean bean) {
        this.bean = bean;
    }
}

This project is bundled into a jar and included as a dependency on my 2nd project:

@Component("bean1")
@Primary
public class Bean1Child extends Bean1 {
}

What I want to happen is for the bean, Bean1Child, to be injected into Bean3's setter method. Unfortunatly I am receiving an error.

org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name 'bean1' for bean class [Bean1Child] conflicts with existing, non-compatible bean definition of same name and class [Bean1]

I needed to use @Qualifier so that Bean2 is not injected into Bean3 Using the @Primary annotation did not help. How can I have Bean1Child injected into Bean3 when running from my 2nd project?


Solution

  • If this is possible, you can change the way the beans are created by removing the @Component annotations:

    In the first project, the BeanChild3 would be refactored to get the bean in the constructor

    public class Bean3 {
        private final Bean bean;
    
        public Bean3(final Bean bean) {
            this.bean = bean;
        }
    }
    

    Then we can create the beans in a BeansConfig class

    @Configuration
    class BeansConfig {
    
       @ConditionalOnMissingBean
       @Bean("bean1")
       Bean bean1(){
          return new Bean1();
       }
    
       @Bean("bean2")
       Bean bean2(){
          return new Bean2();
       }
    
       @Bean("bean3")
       Bean bean3(@Autowired @Qualifier("bean1") Bean){
          return new Bean3(bean);
       }
    
    }
    

    The @ConditionalOnMissingBean allows us to provide another bean with the same name to be used instead. If no such bean exists, then the default one would be used.

    You will then need to create a beanChild1 bean in your second project and it should be picked up.

       @Bean("bean1")
       Bean bean1(){
          return new Bean1Child();
       }