Autowiring Java Generic Types in Spring Framework

Last modified on May 6th, 2015 by Joe.

Spring 4 has introduced many improvements to core container. One among them is autowiring of Java generic types. In this Spring tutorial we will go through what that feature is and how it can be used. This tutorial is suitable for beginners in Spring framework.

From Java 1.5 Annotations and Generics are the most popularly adapted features. Generis provides strong type checking at compile time in Java code.
Spring 3.x framework does not support use of generics in annotations. To leverage Java Generics benefits, Spring 4 has introduced a new feature using which we can autowire generic types. That is we can use Java Generics with Annotations.

Generics as Autowiring Qualifiers

We know that the Spring Framework has an Annotations @Qualifier to provide some qualified name to avoid conflicts. Since Spring 4 we can also use Generics as qualifiers.
Generics as autowiring qualifiers is nothing but the ability to use Java Generic types as implicit qualifiers. Spring IOC Container uses this new feature to resolve conflicts in autowiring bean dependencies. This tutorial is organized as,

To understand this tutorial and accompanying example, we need some working experience with Spring Autowiring and Spring Annotations like @Autowired, @Qualifier etc. Before starting discussion on Spring 4 “Generics as autowiring qualifiers”, its better to know about them in detail. Spring supports five types of autowiring and they are no(default), byType, byName, constructor and autodetect.

@Autowired Annotation

We can use Spring’s @Autowired annotation to autowire bean dependencies automatically by Spring IOC Container. We can use this annotation at constructor, setter method or field level. If a constructor or method has more than one argument, then we use it at argument level. It resolves autowiring by using Bean Type. Example:

public class AlphabetService {

	@Autowired
	private AlphabetGeneratorgenerator;
	
	public AlphabetService(){
		
	}
	
}

Here we are using this annotation at Filed level to inject “AlphabetGenerator” dependency automatically. If we use this annotation at Filed level or Setter method or Method/Constructor Argument level, it uses “byType” autowiring mode. If we use this annotation at Constructor level, it uses “constructor” autowiring mode.

@Qualifier Annotation

It is used to avoid conflicts that occur with @Autowired annotation. If we have more than one bean of same type to autowire with @Autowired annotation, to avoid this conflict we use @Qualifier annotation with some name. We need to use this annotation with @Autowired annotation. @Autowired annotation uses ““Bean Type”” to resolve dependencies, @Qualifier annotation uses “Bean Name”” to do the same.
@Qualifier annotation uses “byName” autowiring mode.

Generics as Autowiring Qualifiers – Example

Let us assume that we have two components. One component is used to generate numbers one by one starting from ‘1’. In the same way, another component to generate alphabets one by one starting from ‘A’.
Let us implement this scenario by using both Spring 3 and Spring 4 and understand the difference.

Let’s first develop in Spring 3. I’m using Spring STS Suite with Maven.

pom.xml

Example using Spring 3

image

pom.xml

pom.xml contains one required dependency. We are using Spring3.2.3.RELEASE version.

<project xmlns=http://maven.apache.org/POM/4.0.0xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javapapers.spring4</groupId>
<artifactId>Spring4.0GenericAutowiringQualifier</artifactId>
<version>1.0.0</version>

<properties>
	<spring-framework.version>3.2.3.RELEASE</spring-framework.version>
</properties>
	
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
	</dependencies>	
</project>

Generator.java

We define an interface to represent number, alphabet for generation process.

package com.javapapers.spring3;

publicinterface Generator<T> {

	T generate();
}

NumberGenerator.java

Extend Generator interface to provide implementation for generating numbers. When we use @Component at class definition, Spring IOC Container automatically generates an implicit qualifier for NumberGenerator bean as ‘numberGenerator’.

package com.javapapers.spring3;

import org.springframework.stereotype.Component;

@Component
public class NumberGenerator implements Generator<Integer>{

	private Integer num = null;
	public NumberGenerator(){
		num = new Integer(1);	
	}
	
	@Override
	public Integer generate(){
		return num++;
	}
}

AlphabetGenerator.java

Now extend Generator interface to provide implementation for generating alphabets. Similarly, Spring IOC Container automatically generates an implicit qualifier for AlphabetGenerator bean as ‘alphabetGenerator’.

package com.javapapers.spring3;

import org.springframework.stereotype.Component;

@Component
public class AlphabetGenerator implements Generator<String>{

	private char alphabet;
	public AlphabetGenerator(){
		alphabet = 65;
	}
	
	@Override
	public String generate(){
		return"" + (alphabet++);
	}
}

AlphabetService.java

Let us include a Service layer for AlphabetGenerator. We are using @Autowired annotation to inject generator bean automatically by Spring IOC Container. AlphabetService calls AlphabetGenerator’s generate() method to generate alphabets.

package com.javapapers.spring3.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.javapapers.spring3.AlphabetGenerator;

@Service
public class AlphabetService {

	@Autowired
	private AlphabetGenerator generator;
	
	public AlphabetService(){	}
	
	public String getAlphabet(){
		return generator.generate();
	}	
}

NumberService.java

A similar service layer for NumberGenerator.

package com.javapapers.spring3.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.javapapers.spring3.NumberGenerator;

@Service
public class NumberService {

	@Autowired
	private NumberGenerator generator;
	
	public NumberService(){
		
	}
	
	public Integer getNumber(){
		return generator.generate();
	}
}

beans.xml

Spring Beans XML Configuration file. We are using Spring Annotation configuration. Just enable Spring annotation and define base package name of all Components as shown below.

<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context.xsd">

		<context:annotation-config/>

		<context:component-scanbase-package="com.javapapers"/>	
</beans>

Spring3AutowiringTest.java

Now it’s time to unit test our example application. We are going to use Spring Test module to write our test client as shown below.

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.javapapers.spring3.service.AlphabetService;
import com.javapapers.spring3.service.NumberService;

public class Spring3AutowiringTest {

	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
		
		NumberService numService = (NumberService)context.getBean("numberService");
		System.out.println(numService.getNumber());
		System.out.println(numService.getNumber());
		
		AlphabetService alphabetService = (AlphabetService)context.getBean("alphabetService");
		System.out.println(alphabetService.getAlphabet());
		System.out.println(alphabetService.getAlphabet());
	}
}

Spring 3 Example Output

image

Example using Spring 4

Now let us see how we will implement the above example using Spring 4’s new feature:“Generics as autowiring qualifiers”

image

pom.xml

Refer previous project pom.xml file. Just change Spring Framework version in “properties” section as below.

<spring-framework.version>4.1.5.RELEASE</spring-framework.version>

Use the same Generator.java, NumberGenerator.java and AlphabetGenerator.java from previous example. No change in these classes.

AlphabetService.java

In Spring 3 example, AlphabetService class directly uses AlphabetGenerator component. That means service layer is tightly coupled with Generator class. It is not a better design.

So instead of this, AlphabetGenerator class uses Generator interface with Generics and @Autowired annotation. We are using Generator with Generics. When container tries to inject generator bean, it searches a bean of type Generator with . AlphabetGenerator implements Generator interface with Generic type. So Container picks this “alphabetGenerator” bean and injects here.

package com.javapapers.spring4.service;

importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
import com.javapapers.spring4.Generator;

@Service
public class AlphabetService {

	@Autowired
	private Generator<String> generator;
	
	public AlphabetService(){
		
	}
	
	public String getAlphabet(){
		returngenerator.generate();
	}
	
}

NumberService.java

package com.javapapers.spring4.service;

importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;

import com.javapapers.spring4.Generator;

@Service
public class NumberService {

	@Autowired
	private Generator<Integer> generator;
	
	public NumberService(){
		
	}
	
	public Integer getNumber(){
		returngenerator.generate();
	}
}

Spring 4 Example Output

Use same beans.xml file and client program from previous example.

image

The ability to autowiring Java generic types is demonstrated. Without this feature, we will not have loose-coupling between these components.

Comments on "Autowiring Java Generic Types in Spring Framework"

  1. Aman Gupta says:

    Nice ! Thanks for updating :)

  2. Rahul Jha says:

    Nice explanation and good example to clear the things out.

    Thanks Joe

  3. Dhaval says:

    Nice Joe..!!

    Thanks a lot.

  4. Siddaling says:

    Your explanation is so simple and easy to understand. thank u….

  5. gdvs says:

    very helpful.Thank you.

  6. kedar says:

    By using Spring 4 ,still I am getting
    nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:

Comments are closed for "Autowiring Java Generic Types in Spring Framework".