When our class contains multiple constructors with same number of
arguments, it will always cause the constructor injection argument type
ambiguities issue in the Spring framework.
In the our example we will see that how ambiguity occurs in the
constructor injection and how to handle this ambiguity issue.
Let's first discuss how ambiguity occurs in constructor injection in the
spring.
When we define the constructor injection in the bean file, spring
decides implicitly which value declared in the constructor-arg, gets assigned
the bean's value in the constructor, by means of three key factors.
- Matching
the quantities or the number of arguments.
- Matching
the type.
- Matching
the order.
Spring try to create bean according to the above defined rules to
resolve which constructor is to be chosen to create the bean. There are below
possible situation can be arised.
- Problem
resolving the constructor(No ambiguity).
- No
problem resolving but the constructor chosen is leading to in-convertible
data( parameter ambiguity).
- No
problem resolving but the constructor chosen is wrong leading to wrong
data(parameter ambiguity).
Let's understand with an example.
Let's create a project say "SpringTutorial" now add the
required jar support to spring, to add the jar you can follow the Spring Tutorial 02 -My First 'Hello World' Program in Spring blog.
Now create a package with the name of "org.javaIsEasy.springConstructorInjectionAmbiguityExample".
Now create a java file with the name of "Rectangle.java" in
this package.
Rectangle.java
*******************************************************************************
package org.javaIsEasy.springConstructorInjectionAmbiguityExample;
public class Rectangle {
private int length;
private int width;
private String message;
Rectangle(int length,String
message, int width)
{
this.length=length;
this.width=width;
this.message=message;
}
Rectangle(int width,int
length,String message)
{
this.length=length;
this.width=width;
this.message=message;
}
public int getLength() {
return length;
}
public int getWidth() {
return width;
}
public String getMessage() {
return message;
}
}
*******************************************************************************
Create an other java file in the same package with the name of
"Area.java".
In the Area file we will creating object of the Rectangle class and
another parameter with the name of 'areaType', we will give the reference of
the Rectangle class in this Area class. So let's see how it goes.
Area.java
*******************************************************************************
package org.javaIsEasy.springConstructorInjectionAmbiguityExample;
public class Area {
private String areaType;
private Rectangle rectangle;
public String getAreaType() {
return areaType;
}
public void setAreaType(String
areaType) {
this.areaType = areaType;
}
public Rectangle getRectangle() {
return rectangle;
}
public void
setRectangle(Rectangle rectangle) {
this.rectangle = rectangle;
}
}
*******************************************************************************
Now create another java file with the name of
"CallAreaApplication.java" in the same package.
This class has the main method, configuration file will be loaded in
this class and let's see how bean is called here.
CallAreaApplication.java
*******************************************************************************
package org.javaIsEasy.springConstructorInjectionAmbiguityExample;
import org.springframework.context.ApplicationContext;
import
org.springframework.context.support.ClassPathXmlApplicationContext;
public class CallAreaApplication {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("org/javaIsEasy/springConstructorInjectionAmbiguityExample/Beans.xml");
Area
area=(Area)context.getBean("AreaBean");
int
length=area.getRectangle().getLength();
int
width=area.getRectangle().getWidth();
String message=area.getRectangle().getMessage();
String
areaType=area.getAreaType();
System.out.println("Area
Name : "+areaType+"\nLength : "+length+"\nWidth :
"+width+"\nArea Value : "+length*width+"\nMessage :
"+message);
}
}
*******************************************************************************
Now we have to create bean configuration file with the name of
"Beans.xml" in the same package.
Here the Beans.xml file is used to define spring bean configuration. The
following code shows how to set a property value through constructor injection.
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="AreaBean"
class="org.javaIsEasy.springConstructorInjectionAmbiguityExample.Area">
<property name="areaType"
value="Rectangle"/>
<property name="rectangle"
ref="RectangleBean"/>
</bean>
<bean
id="RectangleBean"
class="org.javaIsEasy.springConstructorInjectionAmbiguityExample.Rectangle">
<constructor-arg value="Area
Calculated"/>
<constructor-arg value="6"/>
<constructor-arg value="4"/>
</bean>
</beans>
*******************************************************************************
Structure of the project :
Let's run this program to get the result:
Output:
*******************************************************************************
ERROR: Unsatisfied dependency expressed through constructor
argument.......
*******************************************************************************
Now we need to do something resolve this issue.
- We
can resolve this issue by indexing the parameter of the constructor.
Let's apply indexing the "Beans.xml" file.
Modified 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="AreaBean"
class="org.javaIsEasy.springConstructorInjectionAmbiguityExample.Area">
<property name="areaType"
value="Rectangle"/>
<property name="rectangle"
ref="RectangleBean"/>
</bean>
<bean
id="RectangleBean"
class="org.javaIsEasy.springConstructorInjectionAmbiguityExample.Rectangle">
<constructor-arg index="1"
value="Area Calculated"/>
<constructor-arg index="0"
value="6"/>
<constructor-arg index="2"
value="4"/>
</bean>
</beans>
*******************************************************************************
Let's run this program again to get the new result:
Output:
*******************************************************************************
Area Name : Rectangle
Length : 6
Width : 4
Area Value : 24
Message : Area Calculated
*******************************************************************************
We can resolve the issue by indexing the parameter according to the
constructor.
- Now
look at the another way to resolve the ambiguity.
We need to modify the "Beans.xml" again, see how it goes.
Modified 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="AreaBean"
class="org.javaIsEasy.springConstructorInjectionAmbiguityExample.Area">
<property name="areaType"
value="Rectangle"/>
<property name="rectangle"
ref="RectangleBean"/>
</bean>
<bean
id="RectangleBean"
class="org.javaIsEasy.springConstructorInjectionAmbiguityExample.Rectangle">
<constructor-arg name="message"
type="java.lang.String" value="Area Calculated"/>
<constructor-arg name="length"
type="int" value="6"/>
<constructor-arg name="width"
type="int" value="4"/>
</bean>
</beans>
*******************************************************************************
Let's run this program again to get the new result:
Output:
*******************************************************************************
Area Name : Rectangle
Length : 6
Width : 4
Area Value : 24
Message : Area Calculated
*******************************************************************************
We always define the full qualified the parameter with the name and the
type to ignore the ambiguity issue.
No comments:
Post a Comment