Program to demonstrate how to use @Qualifier annotation in Spring Framework in making bean qualify from multiple beans
When it comes to Auto-wiring there can arise a case when there are two or more beans which qualifies to be autowired to a property. In such a scenario, Spring cannot decide that which bean it needs to autowire to. If it fails in deciding, it throws a exception as "org.springframework.beans.factory.NoSuchBeanDefinitionException". See the problem scenario code below :
1. A normal POJO class Side.java having three properties length, pointX and pointY
2. A normal POJO class Triangle.java having Side as property which is auto-wired using @Autowired annotation
3. Spring Configuration XML file having bean declaration for one Triangle class and Two Side class
4. Test class for running the program
Note : When we run the Test class we get an exception trace which is shown below in the image.
Exception Occured on running Test Class :
Now, where is the problem with above code ?.
The problem lies in the Spring Configuration file where there are two beans of class Side. When Spring container finds that Triangle is been Auto-wired to Side class , it checks for Spring Configuration file to fulfill dependency. Here when Spring container scans XML file finds two beans with different id say "side1" and "side2" but of same type Side. It cannot decide which is the right bean developer is looking for. In order to overcome this problem we use @Qualifier annotation, which has value attribute where we set the id for which we need the bean auto-wiring. See the Triangle modified and right code below :
Right Scenario - Providing @Qualifier Annotation in Triangle Class
Output of the program after providing @Qualifier Annotation :
When it comes to Auto-wiring there can arise a case when there are two or more beans which qualifies to be autowired to a property. In such a scenario, Spring cannot decide that which bean it needs to autowire to. If it fails in deciding, it throws a exception as "org.springframework.beans.factory.NoSuchBeanDefinitionException". See the problem scenario code below :
1. A normal POJO class Side.java having three properties length, pointX and pointY
package com.hubberspot.spring.qualifier; public class Side { private int length; private int pointX; private int pointY; public int getLength() { return length; } public void setLength(int length) { this.length = length; } public int getPointX() { return pointX; } public void setPointX(int pointX) { this.pointX = pointX; } public int getPointY() { return pointY; } public void setPointY(int pointY) { this.pointY = pointY; } }
2. A normal POJO class Triangle.java having Side as property which is auto-wired using @Autowired annotation
package com.hubberspot.spring.qualifier; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class Triangle { private Side side; public Side getSide() { return side; } @Autowired public void setSide(Side side) { this.side = side; } }
3. Spring Configuration XML file having bean declaration for one Triangle class and Two Side class
|
4. Test class for running the program
package com.hubberspot.spring.autowire; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.hubberspot.spring.qualifier.Triangle; public class Test { public static void main(String[] args) { // ApplicationContext is a Spring interface which // provides with the configuration for an application. // It provides us with all the methods that BeanFactory // provides. It loads the file resources in a older // and generic manner. It helps us to publish events to the // listener registered to it. It also provides quick support // for internationalization. It provides us with the object // requested, it reads the configuration file and provides // us with the necessary object required. // We are using concrete implementation of ApplicationContext // here called as ClassPathXmlApplicationContext because this // bean factory reads the xml file placed in the classpath of // our application. We provide ClassPathXmlApplicationContext // with a configuration file called as spring.xml placed // at classpath of our application. ApplicationContext context = new ClassPathXmlApplicationContext(("spring.xml")); // In order to get a object instantiated for a particular bean // we call getBean() method of ClassPathXmlApplicationContext // passing it the id for which the object is to be needed. // Here getBean() returns an Object. We need to cast it back // to the Triangle object. Without implementing new keyword we // have injected object of Triangle just by reading an xml // configuration file. Triangle triangle = (Triangle)context.getBean("triangle"); System.out.println("The length of Triangle is : " + triangle.getSide().getLength()); System.out.println("The x co-ordinate of Triangle is : " + triangle.getSide().getPointX()); System.out.println("The y co-ordinate of Triangle is : " + triangle.getSide().getPointY()); } }
Note : When we run the Test class we get an exception trace which is shown below in the image.
Exception Occured on running Test Class :
Now, where is the problem with above code ?.
The problem lies in the Spring Configuration file where there are two beans of class Side. When Spring container finds that Triangle is been Auto-wired to Side class , it checks for Spring Configuration file to fulfill dependency. Here when Spring container scans XML file finds two beans with different id say "side1" and "side2" but of same type Side. It cannot decide which is the right bean developer is looking for. In order to overcome this problem we use @Qualifier annotation, which has value attribute where we set the id for which we need the bean auto-wiring. See the Triangle modified and right code below :
Right Scenario - Providing @Qualifier Annotation in Triangle Class
package com.hubberspot.spring.qualifier; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; public class Triangle { private Side side; public Side getSide() { return side; } @Autowired @Qualifier("side1") public void setSide(Side side) { this.side = side; } }
Output of the program after providing @Qualifier Annotation :