The basic working of spring framework is now clear. Now, we can keep
doing modifications in the existing base project to further build on our
understanding. Let us take up a practical scenario for the next step.
One of the attributes of a class <Candidate> is another class<Address>. The value of the class Candidate depends on the value of the Class Address. i.e., there is a dependency here.
In case of constructor injection, the constructor is used to inject value into the bean. Just like in normal OOP concept, the base class constructor can be used to pass values to the child class constructor.
The end result of setter and constructor injection are the same. Still at times, one might prove to be more advantageous than the other. Now, let us make small modifications to the above classes to inject the values for the attributes using the constructor.
File : Candidate.java
File : Address.java
In case of setter injection, we know that the property values are assigned to the attributes of the class using the setter methods. In that case, default constructor is used for creating the instance. But here in constructor injection , we explicitly pass values to the constructor of the class from the metadata. This means that an explicit constructor has to be provided in the bean classes with parameters appropriate to what is about to be passed from the configuration metadata file.
There is no need to make any changes in the MainClass.java. i.e., the accessing of the objects from a third party remains totally unchanged no matter the type of injection used on these classes.
File : MainClass.java
The obvious change required now, is in the configuration metadata xml (Beans.xml). Instead of setting values using the <property name=” ” value=” ” />(thereby calling the setter method) we can now make use of <constructor-arg> to call the constructor with the appropriate parameters.
File : Beans.xml
<constructor-arg> tag has the index defined to clarify on the value being passed. The value (0,1,2) of the index is in the order of the parameters being passed to the constructor. When one of the parameters to a constructor is an object(as in Address) the value for this object can not be assigned directly. In such cases, uses ref=<beanID>(reference injection) to point that value to the actual bean (bean id=รข”address”). The value for the attributes inside Address is set inside this bean.
In case of constructor injection, the constructor is used to inject value into the bean. Just like in normal OOP concept, the base class constructor can be used to pass values to the child class constructor.
The end result of setter and constructor injection are the same. Still at times, one might prove to be more advantageous than the other. Now, let us make small modifications to the above classes to inject the values for the attributes using the constructor.
Step 1 :
Create Candidate and Address class. Make a note to add constructors to these classes to allow constructor injectionFile : Candidate.java
package com.simpleCodeStuffs; public class Candidate { private String name; private int age; private Address addrs; public Candidate(String name,int age,Address addrs){ this.name=name; this.age=age; this.addrs=addrs; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Address getAddrs() { return addrs; } public void setAddrs(Address addrs) { this.addrs = addrs; } }
Note one small change from the setter injection tutorials in the POJO classes. A constructor has been added to both the POJOs
File : Address.java
package com.simpleCodeStuffs; public class Address { private String doorNo; private String street; private String area; public Address(String doorNo, String street,String area){ this.doorNo=doorNo; this.street=street; this.area=area; } public String getArea() { return area; } public void setArea(String area) { this.area = area; } public String getDoorNo() { return doorNo; } public void setDoorNo(String doorNo) { this.doorNo = doorNo; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } }
In case of setter injection, we know that the property values are assigned to the attributes of the class using the setter methods. In that case, default constructor is used for creating the instance. But here in constructor injection , we explicitly pass values to the constructor of the class from the metadata. This means that an explicit constructor has to be provided in the bean classes with parameters appropriate to what is about to be passed from the configuration metadata file.
In case the parameters passed for the bean from the metadata file and the constructor parameters in the corresponding class does not match, it results in
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘address’ defined in class path resource [Beans.xml]: Could not resolve matching constructor
Step 2 :
There is no need to make any changes in the MainClass.java. i.e., the accessing of the objects from a third party remains totally unchanged no matter the type of injection used on these classes.
File : MainClass.java
package com.simpleCodeStuffs; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainClass { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml"); Candidate can = (Candidate)context.getBean("candidate"); Address add = (Address)context.getBean("address"); System.out.println("Name : "+can.getName()); System.out.println("Age : "+can.getAge()); System.out.println("Address : "+can.getAddrs().getDoorNo()); System.out.println("t "+add.getStreet()); System.out.println("t "+add.getArea()); } }
Step 3:
The obvious change required now, is in the configuration metadata xml (Beans.xml). Instead of setting values using the <property name=” ” value=” ” />(thereby calling the setter method) we can now make use of <constructor-arg> to call the constructor with the appropriate parameters.
File : Beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="candidate" class="com.simpleCodeStuffs.Candidate"> <constructor-arg index="0" value="sandy" /> <constructor-arg index="1" value="22" /> <constructor-arg ref="address" /> </bean> <bean id="address" class="com.simpleCodeStuffs.Address"> <constructor-arg index="0" value="1-B/25" /> <constructor-arg index="1" value="KLN Street" /> <constructor-arg index="2" value="M.K Nagar, Ayapakkam" /> </bean> </beans>
Note that, ‘constructor-arg’ tag is used to inject values from the metadata file in case of constructor injection
<constructor-arg> tag has the index defined to clarify on the value being passed. The value (0,1,2) of the index is in the order of the parameters being passed to the constructor. When one of the parameters to a constructor is an object(as in Address) the value for this object can not be assigned directly. In such cases, uses ref=<beanID>(reference injection) to point that value to the actual bean (bean id=รข”address”). The value for the attributes inside Address is set inside this bean.