5

My Spring+Hibernate configuration files are small and super tight. I use auto scanning to find my model entities/daos.

I don't want to have to write a DAO + DAOImpl for EVERY Entity in my hierarchy.

Some may qualify to have their own, like if they have complex relationships with other entities and require more than basic CRUD functionality. But for the rest...

Is there any way to circumvent the defacto standard?

Say, something like a generic DAO, ex:

http://www.ibm.com/developerworks/java/library/j-genericdao/index.html

Then I can do something like

  GenericDao dao = appContext.getBean("genericDao");
  dao.save(car);            
  dao.save(lease);

Is this possible with annotations? I don't want to have to configure anything in xml. If I cannot do above, is it still possible to have one GenericDaoImpl.java with something like:

 @Repository("carDao")
 @Repository("leaseDao")
 class GenericDaoImpl extends CustomHibernateDaoSupport implements GenericDao {
 ...
 }

and then

  GenericDao dao = appContext.getBean("carDao");
  dao.save(car);            
  dao = appContext.getBean("leaseDao"); //carDao is garbage coll.
  dao.save(lease);

Is this practical at all?

niken
  • 2,499
  • 3
  • 33
  • 56

3 Answers3

5

Using generics, you might try something like this:

@Repository
@Transactional
public class GenericDAOImpl<T> implements GenericDAO<T> {

    @Autowired
    private SessionFactory factory;

    public void persist(T entity) {
        Session session = factory.getCurrentSession();
        session.persist(entity);
    }

    @SuppressWarnings("unchecked")
    public T merge(T entity) {
        Session session = factory.getCurrentSession();
        return (T) session.merge(entity);
    }

    public void saveOrUpdate(T entity) {
        Session session = factory.getCurrentSession();
        session.saveOrUpdate(entity);
    }

    public void delete(T entity) {
        Session session = factory.getCurrentSession();
        session.delete(entity);
    }

}

The content may be different, but the general idea is applicable.

You should be able to then autowire the DAO in your controller and service classes by using

@Autowired
private GenericDAO<Car> carDao;
Beau Grantham
  • 3,435
  • 5
  • 33
  • 43
  • I like this idea, but does it work? I would expect type erasure would lead to a duplicate bean definition, haven't checked this though... – seanhodges Nov 22 '11 at 22:33
  • 1
    Searching around, it looks like you can work around erasure using sub interfaces: http://stackoverflow.com/questions/502994/spring-ioc-and-generic-interface-type – seanhodges Nov 22 '11 at 22:38
  • Just to clarify, Autowired on SessionFactory will autowire Hibernate's SessionFactory in Spring, right? But what if my CustomHibernateDaoSupport extends org.springframework.orm.hibernate3.support.HibernateDaoSupport with an Autowired method which calls setSessionFactory(sessionFactory). So by default other dao's sessions are configured to automatically be managed by Spring... Would these multiple "sessions" impose performance issues? – niken Nov 23 '11 at 14:01
  • 1
    If you are using annotations (and hence Spring 2.5+) I question your use of HibernateDaoSupport at all. Using @Transactional/@Repository will handle DAO "sessions" in much the same way as before, but without tying you to Spring code. see this post for more info: http://stackoverflow.com/questions/5104765/hibernatedaosupport-is-not-recommended-why – seanhodges Nov 24 '11 at 11:54
  • Thanks a lot for clarification Sean, that was very helpful. (I'd vote it up if I could.) – niken Nov 24 '11 at 13:42
  • No problem Nik, hope it works out. Just be aware if you go with this solution you won't be able to @Autowire more than one GenericDAO in a bean, unless you implement non-generic interfaces like "CarDAO", "LeaseDAO", etc – seanhodges Nov 24 '11 at 14:40
  • Wait, what do you mean? In my program I won't be able to have GenericDAO carDao; GenericDAO leaseDao; in one instance? – niken Nov 24 '11 at 16:49
  • That would be fine. Just as long as you never create a "CarDAOImpl" that extends GenericDAOImpl for example. If you do, both beans will declare themselves as "GenericDAO". Sorry, I had a typo in my last comment that made this unclear. – seanhodges Nov 25 '11 at 11:24
2

You can combine Spring/Hibernate with JPA, which provides the EntityManager for a large amount of basic persistence tasks:

@Service
public class CarService {

    @PersistenceContext
    private EntityManager em;

    public void saveCarAndLease(Car car, Lease lease) {
        em.persist(car);
        em.persist(lease);
    }
}

It will also handle transactions and simple queries without needing to write a DAO. For the more complex operations, you can still write a DAO and fall back to Hibernate's SessionFactory (although JPA is an option here too).

Some tutorials suggest you should still write the DAO for abstraction of the JPA plumbing. However, I have personally found this unnecessary (JPA has a very small integration footprint), and in fact this is also the way Spring Roo deals with the data layer behind the scenes.

seanhodges
  • 17,426
  • 15
  • 71
  • 93
1

Have you tried to use Spring Data. I mean to say Spring JPA where you can use repositories.
You can eliminate writing all stuffs for each entity.

Atul
  • 91
  • 4