How To Resolve 'org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean ....' Using @Qualifier Annotation?
Hello everyone, in this article we will learn how to resolve
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.components.Human' available: expected single matching bean but found 2: employee,employer
using @Qualifier Annotation or using @Primary Annotation.
Before going to the example just a quick overview of NoUniqueBeanDefinitionException and @Qualifier Annotation.
NoUniqueBeanDefinitionException:
The 'org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type available: expected single matching bean but found' will be thrown when the bean is auto-wired that matches two or more loaded beans in the spring boot application context. As a result, the bean could not be auto-wired.
The ApplicationContext represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the aforementioned beans.
@Qualifier Annotation:
The @Qualifier annotation is utilized to resolve the autowiring conflict when there are multiple beans of the same type. If we have more than one bean of the same type and optate to wire only one of them then utilize the @Qualifier annotation along with @Autowired to specify which exact bean will be wired.
@Primary Annotation:
@Primary is used to give high preference to the specific bean among multiple beans of the same type to inject into a bean.
Reproduce the issue using the following example,
Human interface:
public interface Human {
public void eat();
}
Employee Bean:
import org.springframework.stereotype.Component;
@Componentpublic class Employee implements Human {
@Override public void eat() { System.out.println("Employee eating");
}}
Employer Bean:
import org.springframework.stereotype.Component;
@Componentpublic class Employer implements Human {
@Override public void eat() { System.out.println("Employer eating");
}}
Human Service:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.example.demo.components.Human;
@Servicepublic class HumanService {
@Autowired private Human human;
public void service() { human.eat(); }}
Spring Boot Main Driver:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import com.example.demo.service.HumanService;
@SpringBootApplicationpublic class DemoApplication implements CommandLineRunner {
@Autowired private HumanService humanService;
public static void main(String[] args) throws Exception { SpringApplication.run(DemoApplication.class, args); }
@Override public void run(String... args) throws Exception { humanService.service();
}}
Exception:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoApplication': Unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'humanService': Unsatisfied dependency expressed through field 'human'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.components.Human' available: expected single matching bean but found 2: employee,employer
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2022-04-24 15:18:08.937 ERROR 13313 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: Field human in com.example.demo.service.HumanService required a single bean, but 2 were found: - employee: defined in file [/home/user/Downloads/spring-quartz-joblistener-demo/target/classes/com/example/demo/components/Employee.class] - employer: defined in file [/home/user/Downloads/spring-quartz-joblistener-demo/target/classes/com/example/demo/components/Employer.class] Action: Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
Solutions
Solution 1: Using @Qualifier Annotation
Injecting Employee bean in HumanService using @Autowired with @Qualifier annotation.
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;import com.example.demo.components.Human;
@Servicepublic class HumanService {
@Autowired @Qualifier("employee") private Human human;
public void service() { human.eat(); }}
Console Output:
Employee eating
Solution 2: Using @Primary Annotation
In the below Employee class, we have added @Primary with @Component annotation. @Primary is used to give high preference to the specific bean among multiple beans of the same type to inject into a bean.
import org.springframework.context.annotation.Primary;import org.springframework.stereotype.Component;
@Component@Primarypublic class Employee implements Human {
@Override public void eat() { System.out.println("Employee eating");
}}
Console Output:
Employee eating