Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring 3.2 Autowire generic types

So I have a number of generics in Spring 3.2 and ideally my architecture would look something like this.

class GenericDao<T>{}  class GenericService<T, T_DAO extends GenericDao<T>> {     // FAILS     @Autowired     T_DAO; }  @Component class Foo{}  @Repository class FooDao extends GenericDao<Foo>{}  @Service FooService extends GenericService<Foo, FooDao>{} 

Unfortunately with multiple implementations of the generics the autowiring throws an error about multiple matching bean definitions. I assume this is because @Autowired processes before type erasure. Every solution I've found or come up with looks ugly to me or just inexplicably refuses to work. What is the best way around this problem?

like image 969
Stephen Lujan Avatar asked Jan 16 '13 21:01

Stephen Lujan


People also ask

What is the default type of Autowire in spring?

The default mode of the @Autowired is byType .

Can we use @autowired in pojo?

The @Autowired annotation in spring automatically injects the dependent beans into the associated references of a POJO class. This annotation will inject the dependent beans by matching the data-type (i.e. Works internally as Autowiring byType).

What is the difference between @bean and @autowired?

@Bean is just for the metadata definition to create the bean(equivalent to tag). @Autowired is to inject the dependancy into a bean(equivalent to ref XML tag/attribute).


2 Answers

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> { } 
like image 187
matsev Avatar answered Sep 16 '22 21:09

matsev


Here is a closest solution. The specialized DAOs are annotated at the business layer. As in the question from OP, the best effort would be having an annotated DAO in the EntityDAO generic template itself. Type erasure seems to be not allowing the specialized type information to get passed onto the spring factories [resulting in reporting matching beans from all the specialized DAOs]

The Generic Entity DAO template

public class EntityDAO<T>  {     @Autowired     SessionFactory factory;      public Session getCurrentSession()     {         return factory.getCurrentSession();     }      public void create(T record)     {         getCurrentSession().save(record);     }      public void update(T record)     {         getCurrentSession().update(record);     }      public void delete(T record)     {         getCurrentSession().delete(record);     }      public void persist(T record)     {         getCurrentSession().saveOrUpdate(record);     }      public T get(Class<T> clazz, Integer id)     {         return (T) getCurrentSession().get(clazz, id);     } } 

The Generic Entity Based Business Layer Template

public abstract class EntityBusinessService<T> implements Serializable {     public abstract EntityDAO<T> getDAO();      //Rest of code. } 

An Example Specialized Entity DAO

@Transactional @Repository public class UserDAO extends EntityDAO<User> { } 

An Example Specialized Entity Business Class

@Transactional @Service @Scope("prototype") public class UserBusinessService extends EntityBusinessService<User> {     @Autowired     UserDAO dao;      @Override     public EntityDAO<User> getDAO()      {         return dao;     }      //Rest of code } 
like image 44
maggu Avatar answered Sep 17 '22 21:09

maggu