How to Autowire Bean of generic type T in Spring?
Simple solution is to upgrade to Spring 4.0 as it will automatically consider generics as a form of @Qualifier
, as below:
@Autowired
private Item<String> strItem; // Injects the stringItem bean
@Autowired
private Item<Integer> intItem; // Injects the integerItem bean
Infact, you can even autowire nested generics when injecting into a list, as below:
// Inject all Item beans as long as they have an <Integer> generic
// Item<String> beans will not appear in this list
@Autowired
private List<Item<Integer>> intItems;
How this Works?
The new ResolvableType
class provides the logic of actually working with generic types. You can use it yourself to easily navigate and resolve type information. Most methods on ResolvableType
will themselves return a ResolvableType
, for example:
// Assuming 'field' refers to 'intItems' above
ResolvableType t1 = ResolvableType.forField(field); // List<Item<Integer>>
ResolvableType t2 = t1.getGeneric(); // Item<Integer>
ResolvableType t3 = t2.getGeneric(); // Integer
Class<?> c = t3.resolve(); // Integer.class
// or more succinctly
Class<?> c = ResolvableType.forField(field).resolveGeneric(0, 0);
Check out the Examples & Tutorials at below links.
- Spring Framework 4.0 and Java Generics
- Spring and Autowiring of Generic Types
Autowiring Beans with Generic typed parameters at runtime
Something like this, I guess:
String [] names = context.getBeanNamesForType(ResolvableType.forClassWithGenerics(Bar.class, Detail.class));
Foo<Detail> bar = context.getBean(names[0]);
Why @Autowired does not work with generic type T?
The reason for this is type erasure which happens at compile time while bean injection happens at runtime.
Since there are no bounds on it T
gets erased and basically replaced by Object
and Spring Data can't create repositories for Object
.
See also Using generics in Spring Data JPA repositories
Spring 3.2 Autowire generic types
How about adding a constructor to the GenericService
and move the autowiring to the extending class, e.g.
class GenericService<T, T_DAO extends GenericDao<T>> {
private final T_DAO tDao;
GenericService(T_DAO tDao) {
this.tDao = tDao;
}
}
@Service
FooService extends GenericService<Foo, FooDao> {
@Autowired
FooService(FooDao fooDao) {
super(fooDao);
}
}
Update:
As of Spring 4.0 RC1, it is possible to autowire based on generic type, which means that you can write a generic service like
class GenericService<T, T_DAO extends GenericDao<T>> {
@Autowired
private T_DAO tDao;
}
and create multiple different Spring beans of it like:
@Service
class FooService extends GenericService<Foo, FooDao> {
}
SpringBoot Autowiring a generic type fails because of multiple possible beans
If you want to autowire all beans that extends TaskService
maybe you should change the autowired field to a List
:
@Component
public class TaskScheduler<T extends TaskService>{
@Autowired
private List<T> taskService;
}
In this way Spring should put in the List
all autowireable beans that extends TaskService
.
EDIT: since you want to dinamically select the type of TaskService
the only way I've found is the following. First, redefine your TaskScheduler
:
public class TaskScheduler <T extends TaskService>{
private T taskService;
public void setTaskService(T taskService) {
this.taskService = taskService;
}
}
Your TaskService
and related subclasses should remain untouched. Set up a configuration class as it follows:
@Configuration
public class TaskConf {
@Autowired
private FirstTaskService firstTaskService;
@Autowired
private SecondTaskService secondTaskService;
@Bean
public TaskScheduler<FirstTaskService> firstTaskServiceTaskScheduler(){
TaskScheduler<FirstTaskService> t = new TaskScheduler<>();
t.setTaskService(firstTaskService);
return t;
}
@Bean
public TaskScheduler<SecondTaskService> secondTaskServiceTaskScheduler(){
TaskScheduler<SecondTaskService> t = new TaskScheduler<>();
t.setTaskService(secondTaskService);
return t;
}
}
And then test your TaskScheduler
in this way:
@Autowired
TaskScheduler<firstTaskService> ts;
Related Topics
Itext - Add Content to Existing PDF File
How to Enable Anti Aliasing in Arbitrary Java Apps
When Should an Illegalargumentexception Be Thrown
Print All the Spring Beans That Are Loaded
Are There Any Other Java Libraries for Bonjour/Zeroconf Apart from Jmdns
Must Issue a Starttls Command First
Spring Session-Scoped Beans (Controllers) and References to Services, in Terms of Serialization
How to Deserialize a Blank JSON String Value to Null for Java.Lang.String
How to "Add" to Classpath Dynamically in Java
In Which Language Are the Java Compiler and Jvm Written
Tomcat - Maxthreads VS Maxconnections
How to Use the Jersey JSON Pojo Support
Sessiontimeout: Web.Xml VS Session.Maxinactiveinterval()