3) @Autowired on Constructors
Following examples shows how to use @Autowired on Constructors.
Case1: Single Constructor with no arguments.
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 Student(){
this.name = "abc";
this.address = "xyz";
this.course = new Course("Computers");
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
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 Student(){
this.name = "abc";
this.address = "xyz";
this.course = new Course("Computers");
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
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 {
private String courseName;
Course(){
this.courseName = "Computers";
}
Course(String c){
this.courseName = c;
}
public void setCourseName(String courseName){
this.courseName = courseName;
}
public String getCourseName(){
return courseName;
}
}
public class Course {
private String courseName;
Course(){
this.courseName = "Computers";
}
Course(String c){
this.courseName = c;
}
public void setCourseName(String courseName){
this.courseName = courseName;
}
public String getCourseName(){
return courseName;
}
}
ApplicationContext.xml
<?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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" />
<bean id="course" class="examples.springanno.Course"/>
</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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" />
<bean id="course" class="examples.springanno.Course"/>
</beans>
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();
}
}
Run the program and you will get following error:
Exception in thread "main" java.lang.IllegalStateException: Autowired annotation requires at least one argument: public examples.springanno.Student()
This is because you cannot put @Autowired annotation on a constructor with no arguments. At least one arguent is required.
To change the constructor move on to case2.
Case2: Single Constructor with one argument.
Change the constructor of Student class as:
@Autowired
public Student(Course c){
this.name = "abc";
this.address = "xyz";
this.course = c;
}
public Student(Course c){
this.name = "abc";
this.address = "xyz";
this.course = c;
}
Here constructor has one argument of type Course. Change the ApplicationContext.xml as:
<?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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<!-- No need to write the following line.
It will be automatically injected into Student constructor using @Autowired.
<constructor-arg name="course" ref="course"/>
-->
</bean>
<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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<!-- No need to write the following line.
It will be automatically injected into Student constructor using @Autowired.
<constructor-arg name="course" ref="course"/>
-->
</bean>
<bean id="course" class="examples.springanno.Course">
<property name="courseName" value="Computer Applications"/>
</bean>
</beans>
Course.java and MainApp.java remains same.
In above code Student constructor has one argument. So ideally bean definition of Student class in ApplicationContext.xml should have been like this:
<bean id="student" class="examples.springanno.Student" >
<constructor-arg name="course" ref="course"/>
</bean>
<constructor-arg name="course" ref="course"/>
</bean>
But we have ommitted the statement
<constructor-arg name="course" ref="course"/>
in above xml file.
This is because Student constructor is annotated with @Autowired. So it will read the bean definition of Course from xml file and automatically inject into the Student constructor.
Output:
Student name : abc
Student Address : xyz
Course Details:
Course Name : Computer Applications
Student Address : xyz
Course Details:
Course Name : Computer Applications
Case3: Single Constructor with multiple arguments.
Replace the constructor of Student class with the following one:
package examples.springanno;
import org.springframework.beans.factory.annotation.Autowired;
public class Student {
private String name;
private String address;
private Course course;
@Autowired
public Student(String name, String address, Course course ){
this.name = name;
this.address = address;
this.course = course;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
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 Student(String name, String address, Course course ){
this.name = name;
this.address = address;
this.course = course;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAddress(String address){
this.address = address;
}
public String getAddress(){
return address;
}
public void setCourse(Course c){
this.course = c;
}
public Course getCourse(){
return course;
}
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());
}
}
and change the ApplicationContext.xml as:
<?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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<constructor-arg name="name" value="abc"/>
<constructor-arg name="address" value="xyz"/>
<!-- No need to write the following line.
It will be automatically injected into Student constructor using @Autowired.
<constructor-arg name="course" ref="course"/>
-->
</bean>
<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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<constructor-arg name="name" value="abc"/>
<constructor-arg name="address" value="xyz"/>
<!-- No need to write the following line.
It will be automatically injected into Student constructor using @Autowired.
<constructor-arg name="course" ref="course"/>
-->
</bean>
<bean id="course" class="examples.springanno.Course">
<property name="courseName" value="Computer Applications"/>
</bean>
</beans>
Course.java and MainApp.java remains same.
Now in Student class we have one constructor with multple arguments. Note that in bean definition of Student class in ApplicationContext.xml we are passing values of only two attributes - name and address as:
<constructor-arg name="name" value="abc"/>
<constructor-arg name="address" value="xyz"/>
<constructor-arg name="address" value="xyz"/>
We are not passing the value for third attribute - course. Its value will be automatically injected by using @Autowired.
Case4: Multiple Constructors
Till now we have only one constructor in our Student class. But when used with multiple constructors in a class, @Autowired has some limitations.
You may know that @Autowired is same as @Autowired(required=true) as by default 'required' is equal to true. See here required [LINK]
i) We cannot use @Autowired on more than one constructor unless all of the @Autowired's have their 'required' attribute equals to false as:
@Autowired(required = false)
For 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 Student(Course c){
System.out.println("In first constructor");
this.name = "abc";
this.address = "xyz";
this.course = c;
}
@Autowired
public Student(String name, String address, Course course ){
System.out.println("In second constructor");
this.name = name;
this.address = address;
this.course = 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 Student(Course c){
System.out.println("In first constructor");
this.name = "abc";
this.address = "xyz";
this.course = c;
}
@Autowired
public Student(String name, String address, Course course ){
System.out.println("In second constructor");
this.name = name;
this.address = address;
this.course = 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());
}
}
ApplicatioContext.xml
<?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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<constructor-arg name="name" value="abc"/>
<constructor-arg name="address" value="xyz"/>
<!-- No need to write the following line.
<constructor-arg name="course" ref="course"/>
-->
</bean>
<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
">
<context:annotation-config/>
<bean id="student" class="examples.springanno.Student" >
<constructor-arg name="name" value="abc"/>
<constructor-arg name="address" value="xyz"/>
<!-- No need to write the following line.
<constructor-arg name="course" ref="course"/>
-->
</bean>
<bean id="course" class="examples.springanno.Course">
<property name="courseName" value="Computer Applications"/>
</bean>
</beans>
Course.java and MainApp.java remains same.
Now in above Student class we have two constructors. Both of them are marked by @Autowired. i.e. @Autowired(required=true)
If you run MainApp.java you will get following error:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Invalid autowire-marked constructor: public examples.springanno.Student(examples.springanno.Course). Found another constructor with 'required' Autowired annotation: public examples.springanno.Student(java.lang.String,java.lang.String,examples.springanno.Course)
This is beacause we cannot mark more than one constructor with @Autowired if any of the @Autowired has its required attribute equals to true i.e required=true.
Now suppose we have one constructor with @Autowired(required=true) and other with @Autowired(required=false) as:
@Autowired(required=false)
public Student(Course c){
System.out.println("In first constructor");
this.name = "abc";
this.address = "xyz";
this.course = c;
}
@Autowired
public Student(String name, String address, Course course ){
System.out.println("In second constructor");
this.name = name;
this.address = address;
this.course = course;
}
public Student(Course c){
System.out.println("In first constructor");
this.name = "abc";
this.address = "xyz";
this.course = c;
}
@Autowired
public Student(String name, String address, Course course ){
System.out.println("In second constructor");
this.name = name;
this.address = address;
this.course = course;
}
If you run the program you will still get following error because of the same reason stated above:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Invalid autowire-marked constructor: public examples.springanno.Student(examples.springanno.Course). Found another constructor with 'required' Autowired annotation: public examples.springanno.Student(java.lang.String,java.lang.String,examples.springanno.Course)
Now annotate all Student constructors with @Autowired(required=false) as:
@Autowired(required=false)
public Student(Course c){
System.out.println("In first constructor");
this.name = "abc";
this.address = "xyz";
this.course = c;
}
@Autowired(required=false)
public Student(String name, String address, Course course ){
System.out.println("In second constructor");
this.name = name;
this.address = address;
this.course = course;
}
public Student(Course c){
System.out.println("In first constructor");
this.name = "abc";
this.address = "xyz";
this.course = c;
}
@Autowired(required=false)
public Student(String name, String address, Course course ){
System.out.println("In second constructor");
this.name = name;
this.address = address;
this.course = course;
}
If you run the program you will get following output:
Output:
In second constructor
Student name : abc
Student Address : xyz
Course Details:
Course Name : Computer Applications
Student name : abc
Student Address : xyz
Course Details:
Course Name : Computer Applications
ii) In case of multiple constructors Spring automatically choose which constructor to call based on the fact that how many arguments we are passing in its bean definition in xml file.
For example in above output second constructor has been called not the first one. This is because in bean definition of Student class we are passing two arguments as:
<bean id="student" class="examples.springanno.Student" >
<constructor-arg name="name" value="abc"/>
<constructor-arg name="address" value="xyz"/>
<!-- No need to write the following line
<constructor-arg name="course" ref="course"/>
-->
</bean>
<constructor-arg name="name" value="abc"/>
<constructor-arg name="address" value="xyz"/>
<!-- No need to write the following line
<constructor-arg name="course" ref="course"/>
-->
</bean>
So the most matching constructor is the second one. Hence it is called.
Now remove the <constructor-arg> from the above bean definition of Student as:
<bean id="student" class="examples.springanno.Student" />
Now the output will be :
Output:
In First constructor
Student name : abc
Student Address : xyz
Course Details:
Course Name : Computer Applications
Student name : abc
Student Address : xyz
Course Details:
Course Name : Computer Applications
This time the most matching constructor is the first one so it has been called.
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