Spring @Qualifier Annotation Example

0

We use Spring’s @Autowired annotation to inject dependencies. If there are more than one bean defined of the same type then based on the member variable name the bean is resolved but what if we use a name which doesn’t match with the bean ID. In such cases, we can rely on Spring’s @Qualifier annotation which can help resolve the auto-wiring conflicts. It may be used on a field or parameter. As the name suggests it is used as a qualifier for candidate beans when auto-wiring. We will also see how it can be used be to annotate a custom annotations that can then in turn be used as qualifiers.

We will use one bean type to create several bean definitions.

BeanA:

package com.javarticles.spring;

public class BeanA {
    private String name;
    
    public BeanA(){}
    
    public BeanA(String name){
        this.name = name;
    }
    
    public String toString() {
        return name == null ? super.toString() : "BeanA(" + name + ")";                
    }
}

Below is a custom annotation annotated with @Qualifier. The default bean ID is ‘A4’. One can use it in place of @Qualifier.

QualifierA4:

package com.javarticles.spring;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import org.springframework.beans.factory.annotation.Qualifier;

@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface QualifierA4 {
    String value() default "A4";
}

We will now define beans in Config class. You will see several flavors of BeanA.

  1. We define couple of beans without any qualifier, with bean IDs beanA and beanA0
  2. Next bean is another instance of BeanA but qualified with @Qualifier
  3. beanA2() and beanA3() are qualified with values ‘A2’ and ‘A3’.
  4. beanA4() is qualified with custom qualifier QualifierA4

Config:

package com.javarticles.spring;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {
    @Bean
    public BeanA beanA() {
        return new BeanA();
    }
    
    @Bean
    public BeanA beanA0() {
        return new BeanA("A0");
    }
    
    @Bean
    @Qualifier
    public BeanA beanA1() {
        return new BeanA("A1");
    }
    
    @Bean
    @Qualifier("A2")
    public BeanA beanA2() {
        return new BeanA("A2");
    }
    
    @Bean
    @Qualifier("A3")
    public BeanA beanA3() {
        return new BeanA("A3");
    }
    
    @Bean
    @QualifierA4
    public BeanA beanA4() {
        return new BeanA("A4");
    }
}

In the below class we auto-wire BeanA type beans. The bean is selected based on either the bean name or the qualifier used. For example, @Qualifier("beanA") will auto-wire bean returned by Config.beanA(), the value passed in will be used as the bean ID. Based on the @Qualifier used it will figure out which bean to inject.
You can also use custom annotation, for example, below will inject beanA4:

@Autowired
@QualifierA4
private BeanA customQualifiedBeanA;

The inner static class InnerConfig contains all beans auto-wired using @Qualifier

QualifierAnnotationExample:

package com.javarticles.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;

@Configuration
@Import(Config.class)
public class QualifierAnnotationExample {

    @Autowired
    @Qualifier("beanA")
    private BeanA beanA;

    @Autowired
    @Qualifier("beanA0")
    private BeanA beanA0;

    @Autowired
    @Qualifier
    private BeanA beanA1;

    @Autowired
    @Qualifier("A3")
    private BeanA beanA3;

    @Autowired
    @QualifierA4
    private BeanA customQualifiedBeanA;

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                QualifierAnnotationExample.class);
        try {
            QualifierAnnotationExample qualifierAnnotationExample = (QualifierAnnotationExample) context
                    .getBean("qualifierAnnotationExample");

            System.out.println("BeanA member: "
                    + qualifierAnnotationExample.getBeanA());

            System.out.println("BeanA1 member: "
                    + qualifierAnnotationExample.getBeanA1());

            System.out.println("Qualified BeanA member: "
                    + qualifierAnnotationExample.getBeanA3());

            System.out.println("Custom Qualified BeanA member: "
                    + qualifierAnnotationExample.getCustomQualifiedBeanA());

            System.out.println("InnerConfig:\n" + context.getBean("innerConfig"));

        } finally {
            context.close();
        }
    }

    public BeanA getBeanA() {
        return beanA;
    }

    public BeanA getBeanA0() {
        return beanA0;
    }

    public BeanA getBeanA1() {
        return beanA1;
    }

    public BeanA getBeanA3() {
        return beanA3;
    }

    public BeanA getCustomQualifiedBeanA() {
        return customQualifiedBeanA;
    }

    @Component("innerConfig")
    static class InnerConfig {
        private BeanA beanA;
        private BeanA beanA0;
        private BeanA beanA1;
        private BeanA beanA2;
        private BeanA beanA3;
        private BeanA beanA4;

        @Autowired
        public InnerConfig(@Qualifier("beanA") BeanA beanA,
                @Qualifier("beanA0") BeanA beanA0, @Qualifier BeanA beanA1,
                @Qualifier("A2") BeanA beanA2, @Qualifier("A3") BeanA beanA3,
                @QualifierA4 BeanA beanA4) {
            this.beanA = beanA;
            this.beanA0 = beanA0;
            this.beanA1 = beanA1;
            this.beanA2 = beanA2;
            this.beanA3 = beanA3;
            this.beanA4 = beanA4;
        }

        public String toString() {
            return "BeanA(" + beanA + "),\nBeanA0(" + beanA0 + "),\nBeanA1("
                    + beanA1 + "),\nBeanA2(" + beanA2 + "),\nBeanA3(" + beanA3
                    + "),\nBeanA4(" + beanA4 + ")";
        }
    }
}

Output:

Feb 18, 2016 12:56:00 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7c3df479: startup date [Thu Feb 18 12:56:00 IST 2016]; root of context hierarchy
BeanA member: com.javarticles.spring.BeanA@70b0b186
BeanA1 member: BeanA(A1)
Qualified BeanA member: BeanA(A3)
Custom Qualified BeanA member: BeanA(A4)
InnerConfig:
BeanA(com.javarticles.spring.BeanA@70b0b186),
BeanA0(BeanA(A0)),
BeanA1(BeanA(A1)),
BeanA2(BeanA(A2)),
BeanA3(BeanA(A3)),
BeanA4(BeanA(A4))
Feb 18, 2016 12:56:00 PM org.springframework.context.annotation.AnnotationConfigApplicationContext doClose
INFO: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@7c3df479: startup date [Thu Feb 18 12:56:00 IST 2016]; root of context hierarchy

Dubious Bean if @Qualifier missing

Below configuration fails with BeanCreationException as there are multiple implementations found for BeanA and spring couldn’t figure out which one to inject. There is no @Qualifier used and the member variable name doesn’t match with any of the bean names.

Here is the error:

WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'failAutowiringExample': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4

FailAutowiringExample:

package com.javarticles.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.javarticles.spring")
public class FailAutowiringExample {

    @Autowired
    private BeanA dubiousBeanA;

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
                FailAutowiringExample.class);
        try {
            FailAutowiringExample qualifierAnnotationExample = (FailAutowiringExample) context
                    .getBean("failAutowiringExample");

            System.out.println("BeanA member: "
                    + qualifierAnnotationExample.getBeanA());
        } finally {
            context.close();
        }
    }

    public BeanA getBeanA() {
        return dubiousBeanA;
    }
}

Output:

Feb 18, 2016 10:41:28 PM org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@7c3df479: startup date [Thu Feb 18 22:41:28 IST 2016]; root of context hierarchy
Feb 18, 2016 10:41:28 PM org.springframework.context.annotation.AnnotationConfigApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'failAutowiringExample': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'failAutowiringExample': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
	at org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84)
	at com.javarticles.spring.FailAutowiringExample.main(FailAutowiringExample.java:16)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.javarticles.spring.BeanA com.javarticles.spring.FailAutowiringExample.dubiousBeanA; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
	at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
	... 12 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.javarticles.spring.BeanA] is defined: expected single matching bean but found 6: beanA,beanA0,beanA1,beanA2,beanA3,beanA4
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
	... 14 more

Download the source code

This was an example about spring @Qualifier annotation.

You can download the source code here: springQualifierAnnotationExamples.zip

About Author

Ram's expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring. You can reach him at rsatish.m@gmail.com

Comments are closed.