This post is part of my series on some of the new Spring 4 features. As of Spring 4, generic types can be used to determine what bean should be dependency injected (either by XML or annotation).
Wiring By Generic Type
An example can help clarify this new feature. Assume you defined your DAO by generic interface (if you haven’t studied Java generic typing, you may want to visit here to learn more).
public class Dao<T> { ... }
Now consider a case were two beans are created in the container using this interface (the example below uses Spring’s Java Configuration option for this purpose).
package com.intertech; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class MyConfiguration { @Bean public Dao<Person> createPersonDao() { return new Dao<Person>(); } @Bean public Dao<Organization> createOrganizationDao() { return new Dao<Organization>(); } }
As of Spring 4, the generic type can be used by the container to determine which bean (by type) to dependency inject. Continuing the example, below the Dao<Person> property would get the Dao<Person> bean defined in the Java Configuration above (and not the Dao<Organization> bean).
@Autowired private Dao<Person> dao;
In the Past
In versions of Spring prior to Spring 4, generics did not help qualify which bean would be dependency injected into the dao property. For example, in an older Spring application (prior to Spring 4), attempting the wiring as laid out here would have resulted in a NoUniqueBeanDefinitionException.
code Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.intertech.Dao com.intertech.Service.dao; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.intertech.Dao] is defined: expected single matching bean but found 2: createPersonDao,createOrganizationDao
This is a nice example. Can you post another one using XML configuration?
Derk,
thanks for reading. As far as I know, this would not be possible in XML.
Great example. Question: do you know how I could specify the generic types when creating a bean in a BeanDefinitionRegistryPostProcessor? I can’t seem to figure out how Spring provides the hints for generic type params to be autowired/injected later…
I threw a gist together to show what I’m hoping for. Any help would be appreciated.
https://gist.github.com/dwelch2344/11406133
dwelch – great question. I spent a couple of hours looking into this and could not come up with a good solution using a GenericBeanDefinition mechanism like you suggested. Unfortunately, the class parameter doesn’t allow for the generic specification. I even tried creating two GenericService beans and then trying to get the types of those beans to create the definitions, but at runtime the generic typing isn’t available through .class call.
Is there a reason why the GenericService beans cannot be defined through other configuration mechanisms – like in an @Configuration file? I’m afraid I don’t have any other solution to your question at this time.
So, my use case is that I need to create an arbitrary number of beans with generic parameters and would like to do so from a JavaConfig file, but their type signatures won’t be known until instantiation. Part of the reason I’d like to do it that way is that then the Spring @Autowired annotations will have the type information available for dependencies.
I was able to get it work by using Javassist to programmatically create concrete subclasses of the config files, but ran into other issues so I scrapped the idea. If you’re curious / it’s helpful to anyone, I’ve posted both the Javassist project and an example of how to programattically load the config files manually.
https://github.com/Lemniscate/javassist-util/blob/master/src/main/java/com/github/lemniscate/util/bytecode/JavassistUtil.java is the standalone utility.
https://github.com/Lemniscate/spring-typed-inject/blob/master/src/test/java/ConfigTest.java shows an example of how to programattically load typed config files — just ignore the TypedInject stuff… that was a massive failure 🙂