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.
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.
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.
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.
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 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>
We define an interface to represent number, alphabet for generation process.
package com.javapapers.spring3; publicinterface Generator<T> { T generate(); }
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++; } }
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++); } }
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(); } }
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(); } }
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>
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()); } }
Now let us see how we will implement the above example using Spring 4’s new feature:“Generics as autowiring qualifiers”
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.
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
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(); } }
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(); } }
Use same beans.xml file and client program from previous example.
The ability to autowiring Java generic types is demonstrated. Without this feature, we will not have loose-coupling between these components.
Comments are closed for "Autowiring Java Generic Types in Spring Framework".
Nice ! Thanks for updating :)
Nice explanation and good example to clear the things out.
Thanks Joe
Nice Joe..!!
Thanks a lot.
Your explanation is so simple and easy to understand. thank u….
very helpful.Thank you.
By using Spring 4 ,still I am getting
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: