0

I'm trying to implement a Generic DAO using the Hibernates Context Sessions. Following was my shot:|

import java.io.Serializable;

public interface GenericDao<T, ID extends Serializable> {

 /** Persist the newInstance object into database */
 ID create(T newInstance);

 /**
  * Retrieve an object that was previously persisted to the database using
  * the indicated id as primary key
  */
 T read(ID primaryKey);

 /** Save changes made to a persistent object. */
 void update(T transientObject);

 /** Remove an object from persistent storage in the database */
 void delete(T persistentObject);
}


import java.io.Serializable;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@SuppressWarnings("unchecked")
public class GenericDaoImpl<T, ID extends Serializable> implements
  GenericDao<T, ID> {
 private SessionFactory sessionFactory;

 public void setSessionFactory(final SessionFactory sessionFactory) {
  this.sessionFactory = sessionFactory;
 }

 @Override
 public ID create(final T newInstance) {
  ID id = null;
  final Session session = sessionFactory.openSession();
  final Transaction tx = session.beginTransaction();
  try {
   id = (ID) session.save(newInstance);
   tx.commit();
   session.close();
  } catch (final Exception e) {
   if (tx != null) {
    tx.rollback();
   }
   e.printStackTrace();
  } finally {
   if (session.isOpen()) {
    session.close();
   }
  }
  return id;
 }

 @Override
 public T read(final ID primaryKey) {
  T id = null;
  final Session session = sessionFactory.openSession();
  final Transaction tx = session.beginTransaction();
  try {
   id = (T) session.get(T, primaryKey);
   tx.commit();
   session.close();
  } catch (final Exception e) {
   if (tx != null) {
    tx.rollback();
   }
   e.printStackTrace();
  } finally {
   if (session.isOpen()) {
    session.close();
   }
  }
  return id;
 }

 @Override
 public void update(final T transientObject) {
  final Session session = sessionFactory.openSession();
  final Transaction tx = session.beginTransaction();
  try {
   session.saveOrUpdate(transientObject);
   tx.commit();
   session.close();
  } catch (final Exception e) {
   if (tx != null) {
    tx.rollback();
   }
   e.printStackTrace();
  } finally {
   if (session.isOpen()) {
    session.close();
   }
  }
 }

 @Override
 public void delete(final T persistentObject) {
  final Session session = sessionFactory.openSession();
  final Transaction tx = session.beginTransaction();
  try {
   session.delete(persistentObject);
   tx.commit();
   session.close();
  } catch (final Exception e) {
   if (tx != null) {
    tx.rollback();
   }
   e.printStackTrace();
  } finally {
   if (session.isOpen()) {
    session.close();
   }
  }
 }
}

applicationContext:

<bean id="domainDao" class="com.foo.dao.DomainDao">
  <property name="sessionFactory">
   <ref bean="sessionFactory"></ref>
  </property>

 </bean>

 <bean id="domainDao2" class="com.foo.dao.GenericDaoImpl">
  <property name="sessionFactory">
   <ref bean="sessionFactory"></ref>
  </property>

 </bean>
 <tx:annotation-driven transaction-manager="txManager" />


 <bean id="txManager"
  class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
 </bean>

Ours is a new application which we are trying to implement using Spring 3.0.3 and Hibernate 3.5.5.

Q1. Although I did implement it and is working, did I do in the correct way?

Q2. How can I implement find() operation using generics?

id = (T) session.get(T, primaryKey);

This line is giving compilation error.

UPDATE: The error is because the first param is of type Class.

public Object get(Class clazz, Serializable id)
           throws HibernateException

Q3. How to convert T to T.class?

Community
  • 1
  • 1
jai
  • 21,519
  • 31
  • 89
  • 120
  • 1
    Please don't tell us what the compilation error is, it's much more fun to guess. – skaffman Aug 26 '10 at 08:59
  • Sorry I didn't get that. Are you serious or was that a sarcastic one :S – jai Aug 26 '10 at 09:16
  • It was sarcasm. And regarding Q3, Generics type information is erased at compile time and thus is not available at runtime. You need to pass the actual class and memorize it where you need it. – hiergiltdiestfu May 27 '14 at 14:29

2 Answers2

4

The following trick is often used in generic DAO classes to access type parameters of actual subclasses:

public abstract class GenericDAO<T, ID extends Serializable> {  
    private Class<T> persistentClass;  
    ...

    @SuppressWarnings("unchecked")
    public GenericDAO() {
        this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public T get(ID id) {
        return (T) session.get(persistentClass, id);
    }

    ...
}

And the actual DAO subclass:

public class FooDAO extends GenericDAO<Foo, Long> {}
axtavt
  • 239,438
  • 41
  • 511
  • 482
2

The generics cannot be used in that way. Change your GenericDAOImpl to have a constrctor that takes the class and use that class in the session.get call. See the example below (it uses JPA instead of Hibernate specific classes).

public class GenericDao<T> {

    @PersistenceContext
    private EntityManager em;

    public EntityManager em() {
        return em;
    }

    public void create(final T entity) {
        em.persist(entity);
    }

    public void update(final T entity) {
        em.merge(entity);
    }

    protected T get(final Class<T> type, final String id) {
        return em.find(type, id);
    }

    public void delete(final T entity) {
        em.remove(entity);
    }

}

public class PersonDao extends GenericDao<Person>{

    public Person get(final String id) {
        return get(Person.class, id);
    }

}

Also, it is better to put @Transactional annotations on business or data services, not on DAOs.

Abhinav Sarkar
  • 23,534
  • 11
  • 81
  • 97