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?
The default mode of the @Autowired is byType .
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).
@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).
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> { }
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]
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); } }
public abstract class EntityBusinessService<T> implements Serializable { public abstract EntityDAO<T> getDAO(); //Rest of code. }
@Transactional @Repository public class UserDAO extends EntityDAO<User> { }
@Transactional @Service @Scope("prototype") public class UserBusinessService extends EntityBusinessService<User> { @Autowired UserDAO dao; @Override public EntityDAO<User> getDAO() { return dao; } //Rest of code }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With