views:

1423

answers:

2

Hi, I'm still quite new to Spring, and I've found it to irritating making all these CRUD DAOs, so I've made a "public class GenericCRUDDAO extends HibernateDaoSupport implements CRUDDAO". In my service objects I then simply say something like

private GenericCRUDDAO<User, Integer> userDAO = new GenericCRUDDAO<User, Integer>();

and no more do I have to write simple DAOs and wire them up. Yay! Except for one thing I'm sure all you experienced Spring developers see right away: I cannot get the Hibernate template inside the GenericCRUDDAO, so doing

HibernateTemplate ht = getHibernateTemplate();

gives me a ht that is null. Not so good. I thought of wiring it in, meaning making a genericCRUDDAO bean and then setting a static AnnotationSessionFactoryBean, but that still wouldn't give me a HibernateTemplate. Any suggestions on how I work around that so that I can have my Hibernate Template?

Any more issues with making a generic CRUD DAO I should be thinking about?

Cheers

Nik

+1  A: 

For many, HibernateTemplate and HibernateDaoSupport are on the outs, and instead injecting a SessionFactory is preferred. Not everyone, mind you, but it is a trend, which I adopted not too long ago, removing HibernateTemplate from my own generic DAO.

This blog has a pretty good summary.

The author's examples should be able to help you get to where you want to be.

SingleShot
Thanks for the tip, I'll read that right away
niklassaers
Thanks, that really helped me out. I wasn't aware that I was learning to use something that was deprecated. Is there the equivalent of HibernateTemplate.bulkUpdate() and HibernateTemplate.loadAll() available? Those were the only ones I'm using that I couldn't find equivalents for.
niklassaers
I have not used the "bulk" methods, but this article appears to have your answer: http://docs.jboss.org/hibernate/stable/core/reference/en/html/batch.html
SingleShot
+1  A: 

GenericDao

Well, to me, if your GenericDAO is 'generic', then you might need only one instance, and do all with that single instance.

I'm sure it doesn't bother you to wire on instance, it's at the repetition that you get mad (and I agree with you).

For example, you could pass the Entity class to a generic method.

  • public void save(Class, E...) : lets you save one or more instances of E type, E being one of your entities.
  • public E load(Class, Long id) : loads an entity.
  • ...

    /** Assuming the entities have a superclass SuperEntity with getIdent(). */
    public class GenericDaoImpl implements GenericDao {
    
    
       /** Save a bunch of entities */
       public void save(SuperEntity... entities) {
         for(SuperEntity entity : entities) {
           getSession().save(entity);
         }
       }
    
    
       /** Load any entity. */
       public <E extends SuperEntity> E load(Class<E> entityClass, Long ident) {
         return (E)getSession().load(entityClass, ident);
       }
    
    
       // other generic methods
    }
    


Variant

In our applications, we actually have a variant for this. Because we have many specific request for each Dao, we need the specific Dao classes anyway (create the class and wire it), so to avoid the special case of a Dao that would not be defined, we make the specific Dao classes right away.

Coding

But in no way we repeat the code. All our Daos extends the GenericDao, providing in the constructor the Class parameter that is needed. Sample code (not complete, simple to get the basic idea):

    public abstract class GenericDaoImpl<E extends SuperEntity> 
        implements GenericDao<E> {

       /** Available for generic methods, so it is not a parameter 
        * for the generic methods. */
       private final Class<E> entityClass;

       protected GenericDaoImpl(Class<E> entityClass) {
         this.entityClass = entityClass;
       }

       // generic implementation ; can be made efficient, as it may 
       // send the orders as a batch
       public void save(E... entities) {
         for(SuperEntity entity : entities) {
           getSession().save(entityClass, entity.getIdent());
         }
         // possibly add flushing, clearing them from the Session ...
       }

       // other generic methods
    }

    public class PersonDaoImpl extends GenericDaoImpl<Person> 
        implements PersonDao {

      /** Constructor, instanciating the superclass with the class parameter. */
      public PersonDaoImpl() {
        super(Person.class);
      }

      /** Specific method. */
      public List<Person> findByAge(int minAge, int maxAge) {
        //....
      }
    }

Wiring

Wiring all the beans is not a fatality. Nowadays, there are many autowiring policies, you don't have to worry about it. See them in Spring
http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-annotation-config

KLE
That is also a good way of doing it. For simplicity I prefer only having to state what kind of DAO I'm dealing with once, though.With regards to wiring, my problem is that I new() the DAOs instead of defining them in the XML, thus there is no autowiring for me, right? Or can I new an object and have it autowired?
niklassaers
@niklassaers Yes, you could. But what is the point of newing your Daos?
KLE
The point is making the correct DAO for one of my many entities in the correct service beans.
niklassaers
@niklassaers In our application, we have 831 entities, each with a corresponding Dao. In each Service class, we inject using Spring the few Daos that correspond to the entities we use in that Service. We never 'new' the Daos, but still have exactly the correct Daos for each Service bean... Even better, the Daos are defined as Singleton in Spring, so we only have one instance of each, no matter how many Services use a specific Dao.
KLE
@KLE To me that sounds very much like 831 copy/paste DAOs? That's what I'm trying to avoid. Most of my DAOs simply do CRUD, and I don't want to have a pile of classes laying around for them, and I don't want a ton of copy/paste configuration either. That's why I new them as needed. Are there any particular drawbacks to this in your experience?
niklassaers
@niklassaers In our application, like I wrote in the answer, we need all the specific Daos because they all have specific queries, so it's not a problem with that. Maybe that will come also in your application sooner or later? But before that, you could use the first variant that I explain in my answer (before the separation line). Would that be helpful to you? Would you like a code sample?
KLE
@KLE Thanks for your input, I totally understand when you have all these different queries. @SingleShot's answer solved my problems, so I'll be going that route for now.
niklassaers