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
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();
}
}
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());
}
}
package com.blogspot.javasolutionsguide.springqualifierdemo.constructor.parameter;
public interface Address {
String getAddress();
}
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";
}
}
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";
}
}
Employee Address is : 123,XYZ,Current State
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
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.