Engineering Full Stack Apps with Java and JavaScript
We saw how to inject primitive types and String properties through setter injection and constructor injection. We will see how to inject other objects. A class might have references to other classes and when an object of the outer class is created, Spring can inject objects for the referenced inner objects as well based on bean definitions. We will follow the xml style configuration here, but this can also be done without using XML.
We will have a Point class with x and y coordinates, and then a Line class that references two Point objects. We will get an instance of the Line class using getBean() and Spring will inject the Point objects into the Line object based on bean definitions.
First, we will see the class files used here and then the Spring xml file that defines beans and their references; you can refer to previous notes on how to compile and execute them with required jars.
package com.javajee.spring;
public class Point {
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
package com.javajee.spring;
public class Line {
private Point pointA;
private Point pointB;
public Point getPointA() {
return pointA;
}
public void setPointA(Point pointA) {
this.pointA = pointA;
}
public Point getPointB() {
return pointB;
}
public void setPointB(Point pointB) {
this.pointB = pointB;
}
public void draw() {
System.out.println("Point A = " + getPointA().getX() + ", "
+ getPointA().getY() + ", Point B = " + getPointB().getX()
+ ", " + getPointB().getY());
}
}
package com.javajee.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestMain {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("spring.xml");
Line line = (Line) context.getBean("line");
line.draw();
}
}
This is the class that needs to be executed.
<?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-4.0.xsd">
<bean id="line" class="com.javajee.spring.Line">
<property name="pointA" ref = "point1"></property>
<property name="pointB" ref = "point2"></property>
</bean>
<bean id="point1" class="com.javajee.spring.Point">
<property name="x" value ="1"></property>
<property name="y" value ="1"></property>
</bean>
<bean id="point2" class="com.javajee.spring.Point">
<property name="x" value ="10"></property>
<property name="y" value ="10"></property>
</bean>
</beans>
This is the bean definition file.
Here the Point beans can be reused in other beans as well. If you want them to be used only for the line bean, you can make it inner to the Line bean, and you may also remove the id as it is not needed to refer to.
<bean id="line" class="com.javajee.spring.Line">
<property name="pointA">
<bean class="com.javajee.spring.Point">
<property name="x" value="1"></property>
<property name="y" value="1"></property>
</bean>
</property>
<property name="pointB" ref="point2"></property>
</bean>
<bean id="point2" class="com.javajee.spring.Point">
<property name="x" value="10"></property>
<property name="y" value="10"></property>
</bean>
I have made point1 as an inner bean for pointA property.
You can also give a name or alias to a bean as:
<bean id="point2" class="com.javajee.spring.Point" name="point2bean">
…
Or
<alias name="point2" alias="point2beanalias"/>
The pointB ref attribute can now point to point2 or point2bean or point2beanalias, all giving the same results. This is because ref attribute can point to an id, name or alias.
Comments
Use of idref in spring configuration
We have two ways to reffer another beans in the spring application context configuration.
A. Using ref tag
B. Using idref tag
ref tag - Used to pass the bean to the calling class
idref tag - Used to pass the name (identifier - a string value) of the bean to the calling class
Here we have class Point.java and class Line.java
By using idref in application context configuration the code will be as followed.
<bean id="line" class="com.spring.io.Line">
<property name="pointA" >
<idref bean="point1"/>
</property>
<property name="pointB" ref="point2"></property>
</bean>
<bean id="point1" class="com.spring.io.Point">
<property name="x" value="10"></property>
<property name="y" value="10"></property>
</bean>
By executing these lines we encounter an exception as: Failed to convert property value of type 'java.lang.String' to required type 'com.spring.io.Point' for property 'pointA';
Because we are trying to refer a type of Point with String type. idref is purely sending a String value.
So accept the String value sent by idref, we will create a variable of type String in class Line.java
private String beanName;
So now in spring.xml we make the following changes.
<bean id="line" class="com.spring.io.Line">
<property name="pointA" ref="point1"></property>
<property name="beanName">
<idref bean="point1"/>
</property>
</bean>
<bean id="point1" class="com.spring.io.Point">
<property name="x" value="10"></property>
<property name="y" value="10"></property>
</bean>
So, main purpose of using idref tag is to validate the presence of bean with the name "point1" at deployment time. If bean is not existing then it throws an exception.