Over a million developers have joined DZone.
Gold Partner

Lessons Learned From Spring’s @Autowired

· Java Zone

Last November we got Spring 2.5 and with it the possibility to use annotations for dependency injection (DI). Annotations can be used instead or mixed with the classic application context file(s) based on XML.

If you compare the former more complex XML configurations with what you still have to keep, after using annotations, it's quite amazing how straightforward the XML becomes. For projects with complex DI configurations it is possible to transfer the configuration in steps.

For our ICEfaces Web application e.g. we started with something like this:


<bean id="businessObject"
class="com.test.BusinessObject"
scope="session">
<aop :scoped-proxy/>
<property name="simpleProperty">
Hello World </property> </bean> <bean id="businessObjectAdministration" class="com.test.BusinessObjectAdministration" scope="session"> <aop :scoped-proxy/> <property name="simpleProperty"> Hello Administrators </property> </bean> <bean id="backingBean" class="com.test.BackingBean" scope="session"> <aop :scoped-proxy/> <property name="businessObject"> <ref bean="businessObject" /> </property> </bean> <bean id="backingBeanAdministration" class="com.test.BackingBeanAdministration" scope="session"> <aop :scoped-proxy/> <property name="businessObjectAdministration"> <ref bean="businessObjectAdministration" /> </property> </bean>

This is pretty verbose. The references can also be written in compact syntax, like this:

<property name="businessObject" ref="businessObject" />

Here are the corresponding classes:


package com.test;
public class BusinessObject {

String simpleProperty;

public void setSimpleProperty(String simpleProperty) {
this.simpleProperty = simpleProperty;
}
public String getSimpleProperty() {
return this.simpleProperty;
}
}

package com.test;
public class BusinessObjectAdministration extends
BusinessObject {

}

package com.test;
public class BackingBean {

BusinessObject businessObject;

public void setBusinessObject(BusinessObject businessObject) {
this.businessObject = businessObject;
}
public String getBusinessObject() {
return this.businessObject;
}
}

package com.test;
public class BackingBeanAdministration {

BusinessObjectAdministration businessObjectAdministration;

public void setBusinessObjectAdministration(
BusinessObjectAdministration businessObjectAdministration) {
this.businessObjectAdministration = businessObjectAdministration;
}
public String getBusinessObjectAdministration() {
return this.businessObjectAdministration;
}
}

Each backing bean in this example uses a corresponding business object, whereas BusinessObjectAdministration is a child of BusinessObject.

Adding Annotations

So, what do we have to change to get this annotation stuff working? The reference attributes in the backing beans get an @Autowired. With this a corresponding Spring bean with the same type is searched during the dependency injection. Additionally, we can skip getter and setter for the reference attributes.


public class BackingBean {

@Autowired
BusinessObject businessObject;

...
}

public class BackingBeanAdministration {

@Autowired
BusinessObjectAdministration businessObjectAdministration;

...
}

With this we can also skip the corresponding properties in the application context:


<bean id="backingBean"
class="com.test.BackingBean" scope="session">
<aop :scoped-proxy/>
</bean>

<bean id="backingBeanAdministration"
class="com.test.BackingBeanAdministration"
scope="session">
<aop :scoped-proxy/>
</bean>

Pretty simple. But, when you deploy this you get an exception. Spring will tell you that it has problems to inject the businessObject reference into backingBean.BusinessObject, because there are two matches. We've an inheritance between BusinessObject and BusinessObjectAdministration. So, both are matched in this case.

Matching via type is not the best solution here. But, there's another annotation that allows to name the Spring bean we wanna be used during the dependency injection, called @Qualifier. It has a parameter, that allows to set the bean's name.

When we add this to the backing beans everything works fine.


public class BackingBean {

@Autowired
@Qualifier("businessObject")
BusinessObject businessObject;

...
}

public class BackingBeanAdministration {

@Autowired
@Qualifier("businessObjectAdministration")
BusinessObjectAdministration businessObjectAdministration;

...
}
Topics:

Published at DZone with permission of Rainer Eschen .

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}