What is @Qualifier annotation in Spring and why it is used


In this tutorial, we will explore the @Qualifier annotation of Spring framework.

1. What does @Qualifier annotation do
2. @Qualifier examples



1. What does @Qualifier annotation do 


@Qualifier annotation helps in resolving the dependency injection ambiguity, when your class's dependency has more than one implementation available in the Spring container.

2. @Qualifier Examples

I have created a Spring Boot project using Spring Initializer. Please have a look at one of my previous post, if you are not aware of how to create a Spring project using Spring Initializer. Here is the link

2.1 @Qualifier used at property(field) level

SpringQualifierDemoApplication
.java

package com.blogspot.javasolutionsguide.springqualifierdemo.property;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringQualifierDemoApplication {
    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringQualifierDemoApplication.class, args);
        Employee employee = applicationContext.getBean(Employee.class);
        employee.displayAddress();
    }
} 
Employee.java
package com.blogspot.javasolutionsguide.springqualifierdemo.property;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Employee {

    @Qualifier("permanentAddress")
    @Autowired
    private Address address;

    public void displayAddress() {
        System.out.println("Employee address is: " + address.getAddress());
    }
}
Address.java
package com.blogspot.javasolutionsguide.springqualifierdemo.property;

public interface Address {
    String getAddress();
}

PermanentAddress.java
package com.blogspot.javasolutionsguide.springqualifierdemo.property;

import org.springframework.stereotype.Component;

@Component("permanentAddress")
public class PermanentAddress implements Address {

    @Override
    public String getAddress() {
        return "345,ABC, Permanent State";
    }
}
CurrentAddress.java
package com.blogspot.javasolutionsguide.springqualifierdemo.property;

import org.springframework.stereotype.Component;

@Component("currentAddress")
public class CurrentAddress implements Address {

    @Override
    public String getAddress() {
        return "123,XYZ, Current State";
    }
}
On Running SpringQualifierDemoApplication.java ,you will see following output :
Employee Address is : 345,ABC,Permanent State

2.2 @Qualifier used as Constructor parameter

SpringQualifierDemoApplication.java
package com.blogspot.javasolutionsguide.springqualifierdemo.constructor.parameter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
public class SpringQualifierDemoApplication {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(SpringQualifierDemoApplication.class, args);
        Employee employee = applicationContext.getBean(Employee.class);
        employee.displayAddress();
    }
}


Employee.java
package com.blogspot.javasolutionsguide.springqualifierdemo.constructor.parameter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

@Component
public class Employee {

    private Address address;

    @Autowired
    public Employee(@Qualifier("currentAddress") Address address) {
        this.address = address;
    }

    public void displayAddress() {
        System.out.println("Employee address is: " + address.getAddress());
    }
}
Address.java
package com.blogspot.javasolutionsguide.springqualifierdemo.constructor.parameter;

public interface Address {
    String getAddress();
}
PermanentAddress.java
package com.blogspot.javasolutionsguide.springqualifierdemo.constructor.parameter;

import org.springframework.stereotype.Component;

@Component("permanentAddress")
public class PermanentAddress implements Address {

    @Override
    public String getAddress() {
        return "345,ABC, Permanent State";
    }
}
CurrentAddress.java
package com.blogspot.javasolutionsguide.springqualifierdemo.constructor.parameter;

import org.springframework.stereotype.Component;

@Component("currentAddress")
public class CurrentAddress implements Address {

    @Override
    public String getAddress() {
        return "123,XYZ, Current State";
    }
}
On Running SpringQualifierDemoApplication.java ,you will see following output :
Employee Address is : 123,XYZ,Current State
2.3 Remove @Qualifier Now just remove @Qualifier one by one in both of the above examples, and run their respective SpringQualifierDemoApplication.java and you will get following exception:
exception encountered during context initialization-cancelling refresh attempt:
        org.springframework.beans.factory.UnsatisfiedDependencyException:Error creating bean with
        name'employee':Unsatisfied dependency expressed through field'address';nested exception
        is org.springframework.beans.factory.NoUniqueBeanDefinitionException:No qualifying bean of
        type'com.blogspot.javasolutionsguide.springqualifierdemo.property.Address'available:
        expected single matching bean but found 2:currentAddress,permanentAddress
All the code of this tutorial can be found here in gitHub 


Summary 

So in this tutorial,
-  We saw how using @Qualifier annotation helps Spring in resolving the conflict when 
there are more than one implementations of our dependent class are present in Spring container.
-  As spring Autowiring by default is byType ,so when we use @Autowired annotation on field or constructor parameter and there are more than one beans of that(autowired) type present in the spring
container,then spring will not be able to understand that which dependency to inject, so it will throw
NoUniqueBeanDefinitionException exception.
- To avoid above exception, we should use @Qualifier annotation with the name of the bean which should be injected. That way it will be clear to Spring that bean with that name has to be injected.

Thanks for reading.