Categories
Spring Spring Core

Spring Qualifier Annotation

Generally Autowired annotation will resolve dependencies based on the Type. If you are having only one Class implementing an interface, then Spring will make use of the Class implementation to resolve dependency. But, in most of the scenarios we have more than one Implementation classes for an Interface. If you use @Autowired in this case, it will throw a NoUniqueBeanDefinitionException at runtime. 

Case 1 : One Implementation Class for an Interface

You can provide Autowired annotation either in Constructor or Setter or Identifier to resolve the above PermanentEmployeeServiceImpl dependency in any Bean. 

@Autowired
	public EmployeeController(EmployeeService employeeSerivce) {
		this.employeeService = employeeSerivce;
	}

This will work fine without causing any exception or error.

Case 2 : Two Implementation Classes for an Interface

In this case if you provide @Autowired as like Case 1, Spring doesn’t know which implementation class should use and throws NoUniqueBeanDefinitionException at runtime. To resolve this conflict we can use @Qualifier annotation along with @Autowired annotation. 

@Qualifier(“permanentEmployeeService”) — Now, Spring will know clearly that PermanentEmployeeServiceImpl has to be used here.

We shall look at each way of using Qualifier annotation in Spring with working example in this article.

Qualifier in Spring

We can use Qualifier annotation in Identifiers, Constructor args and Method args.

Using Qualifier in Constructor

@Autowired
	public EmployeeController(@Qualifier("permanentEmployeeService") EmployeeService employeeService) {
		this.employeeService = employeeService;
	}

Using Qualifier in Methods

@Autowired
public void setEmployeeService(@Qualifier("permanentEmployeeServiceImpl") EmployeeService employeeService) {
		this.employeeService = employeeService;
	}

Using Qualifier in Identifiers

@Autowired
	@Qualifier("permanentEmployeeService")
	private EmployeeService employeeService;

Using Qualifier in Multiple args(Method/Constructor)

@Autowired
public void setEmployeeService(@Qualifier("permanentEmployeeServiceImpl") EmployeeService employeeService, @Qualifier(“employeeManager”) EmployeeManager empManager) {
		this.employeeService = employeeService;
this.empManager = empManager;
	}

For the above Qualifier to be worked properly we need to specify the Bean Name or ID or Qualifier value in XML or Java Configuration.

Corresponding XML Configuration

Type 1 :

<bean class="net.geekcoders.service.PermanentEmployeeSerivceImpl">
		<qualifier value="permanentEmployeeService"></qualifier>
	</bean>

Type 2 : (recommended)

<bean id="permanentEmployeeService" class="net.geekcoders.service.PermanentEmployeeSerivceImpl">
	</bean>

It is always recommended to use an ID or Name attribute to a Bean Definition and use the same name or id in Qualifier to distinguish. You can avoid the additional Qualifier tag in Bean Definition.

Corresponding Java Configuration

@Bean("permanentEmployeeService")
	public EmployeeService permanentEmployeeSerivceImpl() {
		return new PermanentEmployeeSerivceImpl();
	}

The Qualifier name mentioned in “Bean class” and “XML/Java Config ID or Name or Qualifier name” should match.

Example of Constructor Based @Autowiring with @Qualifier annotation

In this example, I have one interface and two implementation classes. One of the implementation classes will be injected to Controller class using Autowired annotation and Qualifier annotation.

The final Project structure will be like below.

I have used the “Java 8” and “Spring 5.2.6” version for this example project.

Step 1 : Maven Project

Create Maven project named “SpringAutowiring” using Eclipse

Step 2 : pom.xml

Add below dependencies in the pom.xml file and save it. Maven automatically downloads the Jar files and its dependency jar files into your project “Maven Dependencies” folder.

<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>5.2.6.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.2.6.RELEASE</version>
		</dependency>
	</dependencies>

Step 3 : Controller Class

Create EmployeeController class under “net.geekcoders.controllers” package and copy below code.

package net.geekcoders.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import net.geekcoders.service.EmployeeService;
public class EmployeeController {	
	private EmployeeService employeeService;
	
	@Autowired
	public EmployeeController(@Qualifier("permanentEmployeeService") EmployeeService employeeService) {
		this.employeeService = employeeService;
	}
	public void addNewEmployee() {
		this.getEmployeeService().addNewEmployee();
	}
	/**
	 * @return the employeeService
	 */
	public EmployeeService getEmployeeService() {
		return employeeService;
	}
	/**
	 * @param employeeService the employeeService to set
	 */
	public void setEmployeeService(EmployeeService employeeService) {
		this.employeeService = employeeService;
	}
}

You can see the usage of @Autowiring and @Qualifier from the above highlighted lines.

Step 4 : Employee Pojo

Create Employee class under “net.geekcoders” package and copy below code.

This is to support Service implementations and controller classes to manipulate the employee’s information.

package net.geekcoders;
public class Employee {
	private String empName;
	private int age;
	/**
	 * @return the empName
	 */
	public String getEmpName() {
		return empName;
	}
	/**
	 * @param empName the empName to set
	 */
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	/**
	 * @return the age
	 */
	public int getAge() {
		return age;
	}
	/**
	 * @param age the age to set
	 */
	public void setAge(int age) {
		this.age = age;
	}
}

Step 5 : Interface

Create EmployeeService interface under “net.geekcoders.service” package and copy below code.

package net.geekcoders.service;
import net.geekcoders.Employee;
public interface EmployeeService {
	void addNewEmployee();
	int getEmployees();
	
	boolean modifyEmployee(Employee emp);
}

Step 6 : Service Implementations

Create PermanentEmployeeServiceImpl and ContractEmployeeServiceImpl classes under the same package as the interface belongs to and copy below code.

PermanentEmployeeServiceImpl.java

package net.geekcoders.service;
import net.geekcoders.Employee;
public class PermanentEmployeeSerivceImpl implements EmployeeService {
	@Override
	public void addNewEmployee() {
		System.out.println("permanentEmployeeServiceImpl : addNewEmployee");
	}
	@Override
	public int getEmployees() {
		System.out.println("permanentEmployeeServiceImpl : getEmployees");
		return 0;
	}
	@Override
	public boolean modifyEmployee(Employee emp) {
		System.out.println("permanentEmployeeServiceImpl : modifyEmployee");
		return false;
	}
}

ContractEmployeeServiceImpl.java

package net.geekcoders.service;
import net.geekcoders.Employee;
public class ContractEmployeeServiceImpl implements EmployeeService {
	@Override
	public void addNewEmployee() {
		System.out.println("contractEmployeeServiceImpl :: addNewEmployee");
	}
	@Override
	public int getEmployees() {
		System.out.println("contractEmployeeServiceImpl :: getEmployees");
		return 0;
	}
	@Override
	public boolean modifyEmployee(Employee emp) {
		System.out.println("contractEmployeeServiceImpl :: modifyEmployee");
		return false;
	}
}

Step 7 : XML Configuration

Create applicationContext.xml file under src folder and copy below bean definition.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
	<context:annotation-config />
	<bean id="employeeController" class="net.geekcoders.controllers.EmployeeController"/>
	<bean id="permanentEmployeeService" class="net.geekcoders.service.PermanentEmployeeSerivceImpl"/>
	<bean id="contractEmployeeService" class="net.geekcoders.service.ContractEmployeeServiceImpl"/>
	
</beans>

<context:annotation-config /> is used here because we are using annotation based configuration.

  • As we are using annotations, we should provide Bean Definition either in the form of XML or Java Configuration with @Bean annotation.
  • I’m using XML Configuration for Bean Definition for code readability. 
  • From the above example, I’m using an ID attribute to distinguish between two Bean definitions of EmployeeService type classes and I’m using the same ID to provide as an argument in Qualifier annotation.

Step 8 : Starter class

Configuring ApplicationContext(IoC Container) in EmployeeStarter class.

package net.geekcoders;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import net.geekcoders.controllers.EmployeeController;
public class EmployeeStarter {
	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
		EmployeeController controller = applicationContext.getBean("employeeController", EmployeeController.class);
		controller.addNewEmployee();
	}
}
  • The above code will Configure IoC Container. ApplicationContext will use the applicationContext.xml file we provided in constructor.
  • After IoC Container gets configured, it will Create, Instantiate and Configure all the bean’s defined in applicationContext.xml file and make those ready for use.

Finally run the above application from EmployeeStarter class as a normal java application. You can see the below output logged in the console.

Hence, IoC Container took PermanentEmployeeServiceImpl based on the Qualifier we gave. 

You can change the Qualifier value in EmployeeController class to “contractEmployeeService” and run the application. You can see the IoC Container will pick ContractEmployeeServiceImpl class now and prints the below output.

That’s all for now on Qualifier Annotation in Spring with an example article.

Happy Reading!!!

2 replies on “Spring Qualifier Annotation”

Leave a Reply

Your email address will not be published. Required fields are marked *