NoUniqueBeanDefinitionException: No qualifying bean of type available: expected single matching bean but found 2:

The spring boot exception org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type available: expected single matching bean but found occurs when the bean is auto-wired that matches two or more loaded beans in the spring boot application context. When the bean is auto-wired in the spring boot, two or more beans are found in the context. As a result, the bean could not be auto-wired. 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 expected single matching bean but found 2:

When an interface or abstract class is implemented with two or more instances, these instance classes can be invoked using an interface or abstract. If the spring boot application is auto-wired with an interface or abstract class, multiple instances of the implemented class would be available for auto-wire. As a result, the bean could not be auto-wired. The exception NoUniqueBeanDefinitionException: No qualifying bean of type available: expected single matching bean but found will be thrown.

The spring boot application will allow to create two or more beans from a single class. If the bean is auto-wired, these two or more beans have been found to be auto-wired. As a result, the bean could not be auto-wired. The exception org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type available will be thrown.



Exception

The exception org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type available: expected single matching bean but found stack trace would be similar to the one seen below.

2020-12-09 11:50:40.365  WARN 25121 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'zoo': Unsatisfied dependency expressed through field 'animal'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.yawintutor.Animal' available: expected single matching bean but found 2: lion,tiger
2020-12-09 11:50:40.372  INFO 25121 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-12-09 11:50:40.394 ERROR 25121 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Field animal in com.yawintutor.Zoo required a single bean, but 2 were found:
	- lion: defined in file [/SpringBootBean/target/classes/com/yawintutor/Lion.class]
	- tiger: defined in file [/SpringBootBean/target/classes/com/yawintutor/Tiger.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


Root Cause

When the spring boot application is starting, the Spring boot application loads the beans into the ApplicationContext. Subsequently, the dependent beans are added to produce other types of beans. If two or more beans are available to be injected for a bean, an exception “NoUniqueBeanDefinitionException: No qualifying bean of type available: expected single matching bean but found” will be thrown.



How to reproduce this exception

When two or more beans are created for a class or two or more of the class objects implemented for an interface, the exception will be created. In this example, an interface of two classes is created. If the interface is auto-wired with the @Autowired annotation, the bean could not be auto-wired.

package com.yawintutor;

public interface Animal {
	public String getName();
}
package com.yawintutor;

import org.springframework.stereotype.Component;

@Component
public class Lion implements Animal{
	@Override
	public String getName() {
		return "Lion";
	}
}
package com.yawintutor;

import org.springframework.stereotype.Component;

@Component
public class Tiger implements Animal{
	@Override
	public String getName() {
		return "Tiger";
	}
}
package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Zoo {

	@Autowired
	public Animal animal;
}

Output

2020-12-09 11:50:40.365  WARN 25121 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'zoo': Unsatisfied dependency expressed through field 'animal'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.yawintutor.Animal' available: expected single matching bean but found 2: lion,tiger
2020-12-09 11:50:40.372  INFO 25121 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-12-09 11:50:40.394 ERROR 25121 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Field animal in com.yawintutor.Zoo required a single bean, but 2 were found:
	- lion: defined in file [/SpringBootBean/target/classes/com/yawintutor/Lion.class]
	- tiger: defined in file [/SpringBootBean/target/classes/com/yawintutor/Tiger.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


Solution 1

Spring boot auto-wire works with the Java naming convention variable name. If a bean is created with a variable that matches the implemented class name of the java naming convention variable, the annotation @Autowired can use the implemented class to auto-wire. The exception will be resolved.

In the example below the name of the variable is lion. “lion” is the name of the Java convention variable for the “Lion” class. This is why the @Autowired annotation uses the Lion class bean object to autowire the variable.

package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Zoo {

	@Autowired
	public Animal lion;
}


Solution 2

The auto-wire of the spring boot will work based on the data type. If the data type of the class matches the loaded bean, the bean will be automatically wired to the variable. Therefore, instead of using the interface or abstract class name, use the implemented class to auto-wire the spring boot bean.

The variable animal is created using the implemented class in the example below. Auto-wire creates a bean of the type “Lion” and assigns it to the variable “animal”

package com.yawintutor;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class Zoo {

	@Autowired
	public Lion animal;
}


Solution 3

If one of the classes introduced is included in the auto-wire, the class should be annotated with @Primary. The annotated @Primary class is considered to be the default class in the auto-wire. The @Autowired annotation loads the @Primary bean and adds an interface or abstract variable to it.

In the example below the @Primary annotation is used to register as a default bean. The @Autowired annotation would use the bean to auto-wire the variable.

package com.yawintutor;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

@Component
@Primary
public class Lion implements Animal{
	@Override
	public String getName() {
		return "Lion";
	}
}


Solution 4

The spring boot annotation @Qualifier is used to choose a bean from a multiple bean. The @Qualifier annotation will be configured to match the bean name. The @Autowired annotation uses the name of the qualifier to match and load the bean.

package com.yawintutor;

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

@Service
public class Zoo {

	@Autowired
	@Qualifier("lion")
	public Animal animal;
}


Solution 5

If the auto-wire is configured with a class method, The qualifier is used along with the method parameters. The example below will show the annotation @Autowired with a method. The method parameter is injected with annotation @Qualifier.

package com.yawintutor;

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

@Service
public class Zoo {

	private Animal animal;

	@Autowired
	public vod setAnimal(@Qualifier("lion") Animal animal){
		this.animal = animal;
	}
}



Leave a Reply