Ad

Thursday 5 March 2015

No unique bean of type [] is defined: expected single matching bean but found 2

In this post we will see how to resolve the exception-"NoSuchBeanDefinitionException:No unique bean of type [] is defined: expected single matching bean but found 2" in spring.By using autowiring feature in spring,we can make the spring container to resolve the bean dependencies automatically and hence we don't need to declare the dependencies either through constructor arguments or through properties in the application context file.We can autowire the beans by:
  • ByName  - spring container will autowire the dependencies by looking up the bean name in the application context file which will match with the bean property name.Lets says  a bean X has the property y(has the setY method too) and the  spring container will look for the bean named "y" in the application context and inject the same to bean X.
  • ByType   - spring container will autowire the property with the bean which has the same type.If more than one bean exists in the container of the same type,then the above fatal exception is thrown
  • Constructor - Its as same as ByType,but it applies to the argument type of the bean to be autowired.If more than one bean or no bean exist in the container of the same constructor type then the above fatal exception is thrown.
Let say we have the below classes and we would like to autowire the  dependencies by type.
  • Bus - Bean class for which the container has to autowire the dependencies by type.
  • Engine - Bean class which is set as the property of the bus object.
  • BusDemo -Main class which will load the spring container and get the bus bean from the container.
  • buscontext.xml - metadata configuration details for the spring container.
Bus.java

package test;

public class Bus {
private Engine engine=null;

public Engine getEngine() {
return engine;
}

public void setEngine(Engine engine) {
this.engine = engine;
}

        @Override
public String toString() {
return "Bus [engine=" + engine + "]";
}
}
   

Engine.java

package test;

public class Engine {
private String engineMake;
private String engineCost;

public String getEngineMake() {
return engineMake;
}

public void setEngineMake(String engineMake) {
this.engineMake = engineMake;
}

public String getEngineCost() {
return engineCost;
}

public void setEngineCost(String engineCost) {
this.engineCost = engineCost;
}
       
        @Override
public String toString() {
return "Engine [engineMake=" + engineMake + ", engineCost="
+ engineCost + "]";
}

buscontext.xml


<?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:aop="http://www.springframework.org/schema/aop" 
xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<bean id="bus" class="test.Bus" autowire="byType">
</bean>

<bean id="primaryengine" class="test.Engine">
<property  name="engineMake" value="Ford"/>
<property  name="engineCost" value="100000"/>
</bean>

<bean id="secondaryengine" class="test.Engine">
<property  name="engineMake" value="Renault"/>
<property  name="engineCost" value="50000"/>
</bean>

</beans>

As we can see in the application context file,we use the attribute autowire="byType" to make the container to automatically inject and resolve the dependencies for the bus bean.Container will look for the bean of type "test.Engine" and inject the same to the engine property of the bus bean.

BusDemo.java

package test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class BusDemo {
public static void main(String[] args) {
ApplicationContext bf= new ClassPathXmlApplicationContext(new String[]  
               {"buscontext.xml"});
Bus bus= bf.getBean("bus",Bus.class);
       System.out.println(bus);
}

}

OUTPUT:

When we run the main program - BusDemo,we will get the below exception

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'bus' defined in class path resource [buscontext.xml]: Unsatisfied dependency expressed through bean property 'engine': : No unique bean of type [test.Engine] is defined: expected single matching bean but found 2: [primaryengine, secondaryengine]; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [test.Engine] is defined: expected single matching bean but found 2: [primaryengine, secondaryengine]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType
(AbstractAutowireCapableBeanFactory.java:1167)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean
(AbstractAutowireCapableBeanFactory.java:1059)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean
(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean
(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject
(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton
(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean
(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean
(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons
(DefaultListableBeanFactory.java:580)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization
(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh
(AbstractApplicationContext.java:464)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:93)
at test.BusDemo.main(BusDemo.java:9)

While autowiring the dependencies for the bus bean, container found two beans of type  test.Engine instead of one and hence this exception was thrown

We can resolve this exception either in two ways.Let say we want the container to autowire the dependency for the bus bean with the primaryengine bean.

1)Set the primary attribute of the primaryengine bean to true,so that the container will nominate this bean to inject it to the bus bean by autowiring

   <bean id="primaryengine" class="test.Engine" primary="true">
   <property  name="engineMake" value="Ford"/>
   <property  name="engineCost" value="100000"/>
   </bean>

or

2)Set the autowire-candidate attribute of the secondaryengine bean to false,so that the container will exclude this bean for autowiring  and hence inject the primaryengine bean to the bus bean. 

<bean id="secondaryengine" class="test.Engine" autowire-candidate="false">
<property  name="engineMake" value="Renault"/>
<property  name="engineCost" value="50000"/>
</bean>

Now if we run the BusDemo with the change(either option 1 or 2 as above) in the buscontext.xml,we get the below output

Bus [engine=Engine [engineMake=Ford, engineCost=100000]]

No comments:

Post a Comment