@Autowired and @Qualifier Annotations for Spring


We use @Autowired to automatically wire our bean dependencies.

Example

In the following example, we have autowired the home address for our student from the previous example. Spring will look for a single bean with a type that matches the type for home. If it finds this bean then it will automatically inject that bean into the Student bean. If it finds more than one bean of that type then it will cause an error.

Student.java

From the previous example we have only added the home property.

package com.skills421.examples.spring.model;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;

public class Student
{
private String name;
private String email;
private String studentId;
private Address home;

public String getName()
{
return name;
}

public void setName(String name)
{
this.name = name;
}

public String getEmail()
{
return email;
}

public void setEmail(String email)
{
this.email = email;
}

public String getStudentId()
{
return studentId;
}

@Required
public void setStudentId(String studentId)
{
this.studentId = studentId;
}

public Address getHome()
{
return home;
}

@Autowired
public void setHome(Address home)
{
this.home = home;
}

public String toString()
{
StringBuilder sb = new StringBuilder("Student[");
sb.append("name="+name);
sb.append(", email="+email);
sb.append(", studentId="+studentId);
sb.append(", home="+home);
sb.append("]");

return sb.toString();
}

}

Address.java

package com.skills421.examples.spring.model;

import java.util.List;

public class Address
{
private List<String> addressLines;
private String town;
private String county;
private String postcode;

public Address()
{

}

public Address(List<String>addressLines, String town, String county, String postcode)
{
this.addressLines = addressLines;
this.town = town;
this.county = county;
this.postcode = postcode;
}

public List<String> getAddressLines()
{
return addressLines;
}

public void setAddressLines(List<String> addressLines)
{
this.addressLines = addressLines;
}

public String getTown()
{
return town;
}

public void setTown(String town)
{
this.town = town;
}

public String getCounty()
{
return county;
}

public void setCounty(String county)
{
this.county = county;
}

public String getPostcode()
{
return postcode;
}

public void setPostcode(String postcode)
{
this.postcode = postcode;
}

public String toString()
{
StringBuilder sb = new StringBuilder("Address[");

if(addressLines!=null)
{
sb.append("addreslines=[");

int count=0;

for(String line : addressLines)
{
if(count>0) sb.append(", ");
sb.append(line);
count++;
}

sb.append("]");
}

sb.append(", town="+town);
sb.append(", county="+county);
sb.append(", postcode="+postcode);
sb.append("]");

return sb.toString();
}
}

student1.xml

From the previous example we have simply added a single address bean for london and we have added the AutowiredAnnotationBeanPostProcessor bean.

<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.xsd">

<!-- Person Beans -->
<bean id="jondoe" class="com.skills421.examples.spring.model.Student">
<property name="name" value="Jon Doe" />
<property name="email" value="jon.doe@gmail.com" />
<property name="studentId" value="DoeJ-001" />
</bean>

<!-- Address Beans -->
<bean id="london" class="com.skills421.examples.spring.model.Address">
<property name="addressLines">
<list>
<value>House of Commons</value>
<value>Parliament Square</value>
</list>
</property>
<property name="town" value="London" />
<property name="county" value="Greater London" />
<property name="postcode" value="SW1 1AA" />
</bean>

<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
</beans>

TestStudent1.java

finally, our Test suite remains unchanged from our previous example.

package com.skills421.example.spring;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.skills421.examples.spring.model.Student;

public class TestStudent1
{
private static AbstractApplicationContext context;

@BeforeClass
public static void setupAppContext()
{
context = new ClassPathXmlApplicationContext("student1.xml");
}

@AfterClass
public static void closeAppContext()
{
if(context!=null)
{
context.close();
}
}

@After
public void printBlankLine()
{
System.out.println();
}

@Test
public void test1()
{
System.out.println("jondoe");
Student person = context.getBean("jondoe",Student.class);
System.out.println(person);
}
}

Problems

If we have more than one address bean defined then Spring will perform the following, in order:

  1. If only one bean of type Address then autowire it
  2. More than one bean of type Address, look for a bean of Type with a name that matches the property name (home)

However, if there is no bean with a name that matches the property name, then we have to find another way to specify which Address bean to use:

@Qualifier

If we add a second address to our Spring config then our @Autowire will not know which address to use for home.

student1.xml

<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.xsd">

<!-- Person Beans -->
<bean id="jondoe" class="com.skills421.examples.spring.model.Student">
<property name="name" value="Jon Doe" />
<property name="email" value="jon.doe@gmail.com" />
<property name="studentId" value="DoeJ-001" />
</bean>

<!-- Address Beans -->
<bean id="london" class="com.skills421.examples.spring.model.Address">
<property name="addressLines">
<list>
<value>House of Commons</value>
<value>Parliament Square</value>
</list>
</property>
<property name="town" value="London" />
<property name="county" value="Greater London" />
<property name="postcode" value="SW1 1AA" />
</bean>

<bean id="manchester" class="com.skills421.examples.spring.model.Address">
<constructor-arg index="0">
<list>
<value>14 Town Plaza</value>
<value>Inner Township</value>
</list>
</constructor-arg>
<constructor-arg index="1" value="Manchester" />
<constructor-arg index="2" value="Greater Manchester" />
<constructor-arg index="3" value="MC15 1AA" />
</bean>

<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
</beans>

Student.java

We resolve this by addding an @Qualifier annotation to our setHome method.

package com.skills421.examples.spring.model;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Required;

public class Student
{
private String name;
private String email;
private String studentId;
private Address home;

public String getName()
{
return name;
}

public void setName(String name)
{
this.name = name;
}

public String getEmail()
{
return email;
}

public void setEmail(String email)
{
this.email = email;
}

public String getStudentId()
{
return studentId;
}

@Required
public void setStudentId(String studentId)
{
this.studentId = studentId;
}

public Address getHome()
{
return home;
}

@Autowired
@Qualifier("london")
public void setHome(Address home)
{
this.home = home;
}

public String toString()
{
StringBuilder sb = new StringBuilder("Student[");
sb.append("name="+name);
sb.append(", email="+email);
sb.append(", studentId="+studentId);
sb.append(", home="+home);
sb.append("]");

return sb.toString();
}

}

and now Spring knows to use the london bean for our home address.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s