While using @Autowired some ambiguities may arise when:
1) Matching bean is not defined OR
2) There are multiple matching beans defined.
1) Matching bean is not defined
Coming back to our Student example:
Student.java
package examples.springanno;
import org.springframework.beans.factory.annotation.Autowired;
public class Student {
private String name;
private String address;
private Course course;
@Autowired
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
// other setters and getters...
public void displayInfo(){
System.out.println("Student name : "+name);
System.out.println("Student Address : "+address);
System.out.println(" Course Details:");
System.out.println(" Course Name : "+this.course.getCourseName());
}
}
import org.springframework.beans.factory.annotation.Autowired;
public class Student {
private String name;
private String address;
private Course course;
@Autowired
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
// other setters and getters...
public void displayInfo(){
System.out.println("Student name : "+name);
System.out.println("Student Address : "+address);
System.out.println(" Course Details:");
System.out.println(" Course Name : "+this.course.getCourseName());
}
}
Course.java
package examples.springanno;
public class Course {
String courseName;
public void setCourseName(String courseName){
this.courseName = courseName;
}
public String getCourseName(){
return courseName;
}
}
public class Course {
String courseName;
public void setCourseName(String courseName){
this.courseName = courseName;
}
public String getCourseName(){
return courseName;
}
}
MainApp.java
package examples.springanno;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String args[]){
ApplicationContext ctx=new ClassPathXmlApplicationContext("resources/ApplicationContext.xml");
Student student = (Student)ctx.getBean("student");
student.displayInfo();
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String args[]){
ApplicationContext ctx=new ClassPathXmlApplicationContext("resources/ApplicationContext.xml");
Student student = (Student)ctx.getBean("student");
student.displayInfo();
}
}
ApplicationContext.java
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- Enabling Spring to use @Autowired-->
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<property name="name" value="abc"/>
<property name="address" value="xyz"/>
<!-- No need to write this.
<property name="course" ref="course"/>
-->
</bean>
<!-- No Course bean / matching bean defined.
<bean id="course" class="examples.springanno.Course">
<property name="courseName" value="Computer Applications"/>
</bean>
-->
</beans>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- Enabling Spring to use @Autowired-->
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<property name="name" value="abc"/>
<property name="address" value="xyz"/>
<!-- No need to write this.
<property name="course" ref="course"/>
-->
</bean>
<!-- No Course bean / matching bean defined.
<bean id="course" class="examples.springanno.Course">
<property name="courseName" value="Computer Applications"/>
</bean>
-->
</beans>
In the student class above setCourse() method has been annotated with @Autowired. So it will look for a bean whose type is Course in the ApplicationContext.xml. But there is no such bean defined in ApplicationContext.xml whose type is Course.Therefore upon running it, you will get following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [examples.springanno.Course] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
Here the role of @Autowired's 'required' attribute comes into play. By default the value of required attribute is true. So '@Autowired' is same as '@Autowired(required = true)'. 'required = true' means @Autowired will first search for the matching bean in xml file whose type is same as that of property. If no such bean found then it will throw exception.
In order to avoid the above exception change the @Autowired annotation on setCourse() method as :
@Autowired(required = false)
public void setCourse(Course c){
this.course = c;
}
public void setCourse(Course c){
this.course = c;
}
'required = false' means if no matching bean found then instead of throwing an exception it will set this property to null i.e course = null;
2) There are multiple matching beans defined
Now suppose there are more than one matching beans defined in xml configuration file. For example,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- Enabling Spring to use @Autowired-->
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<property name="name" value="abc"/>
<property name="address" value="xyz"/>
<!-- No need to write this.
<property name="course" ref="course"/>
-->
</bean>
<bean id="course" class="examples.springanno.Course">
<property name="courseName" value="Computer Applications"/>
</bean>
<bean id="course1" class="examples.springanno.Course">
<property name="courseName" value="Computers"/>
</bean>
</beans>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- Enabling Spring to use @Autowired-->
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<property name="name" value="abc"/>
<property name="address" value="xyz"/>
<!-- No need to write this.
<property name="course" ref="course"/>
-->
</bean>
<bean id="course" class="examples.springanno.Course">
<property name="courseName" value="Computer Applications"/>
</bean>
<bean id="course1" class="examples.springanno.Course">
<property name="courseName" value="Computers"/>
</bean>
</beans>
In above xml file there are two beans defined whose type is Course. Both are eligible candidates to get autowired at setCourse() setter method of Student class. So which one Spring will choose?
It will throw an exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [examples.springanno.Course] is defined: expected single matching bean but found 2: [course, course1]
To avoid above exception we need @Qualifier annotation as:
package examples.springanno;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Student {
private String name;
private String address;
private Course course;
@Autowired
@Qualifier("course1")
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
//Other setters and getters.
public void displayInfo(){
System.out.println("Student name : "+name);
System.out.println("Student Address : "+address);
System.out.println(" Course Details:");
System.out.println(" Course Name : "+this.course.getCourseName());
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Student {
private String name;
private String address;
private Course course;
@Autowired
@Qualifier("course1")
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
//Other setters and getters.
public void displayInfo(){
System.out.println("Student name : "+name);
System.out.println("Student Address : "+address);
System.out.println(" Course Details:");
System.out.println(" Course Name : "+this.course.getCourseName());
}
}
In above code we have annotated setCourse() method with @Qualifier annotation also. Now Spring will search a bean in xml file whose type is Course but with id course1. So now bean with id course is not an eligible candidate for autowiring,
Course.java and MainApp.java remains the same as above.
If you run the program you will following output:
Output:
Student name : abc
Student Address : xyz
Course Details:
Course Name : Computers
Student Address : xyz
Course Details:
Course Name : Computers
I would like to know your comments and if you liked the article then please share it on social networking buttons.
No comments:
Post a Comment