Here, I would like to propose you a good practice concerning the implementation of GenericDao because the basic operations for data persistence are all identical independently of object to save, the methods in question are those of a CRUD: registration (Create), reading (Read), Update (Update) and deletion (Delete).
So, don’t repeat the DAO!!!! in order to increase our code’s productivity due to a GenericDao.
Generic DAO
Following, the steps to implement a generic DAO in ORM system:
- Firstly, we need a generic DAO interface which contains the common CRUD available methods, our other specific DAO interfaces must extend it:
01 | public interface GenericDao<T, PK extends Serializable> { |
02 | PK create(T persistentObject); |
08 | void update(T persistentObject); |
10 | void createOrUpdate(T persistentObject); |
12 | void delete(T persistentObject); |
- Then, the implementation of above interface is simple, but, the other DAO implementations will also extend it:
01 | @Transactional (propagation=Propagation.MANDATORY) |
02 | public class GenericDaoImpl<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> { |
04 | private Class<T> type; |
06 | public GenericDaoImpl(SessionFactory sessionFactory, Class<T> type) { |
07 | super .setSessionFactory(sessionFactory); |
11 | @SuppressWarnings ( "unchecked" ) |
12 | public PK create(T o) { |
13 | return (PK) getSession().save(o); |
16 | @SuppressWarnings ( "unchecked" ) |
17 | @Transactional (propagation=Propagation.REQUIRED, readOnly= true ) |
19 | T value = (T) getSession().get(type, id); |
24 | if (value instanceof HibernateProxy) { |
25 | Hibernate.initialize(value); |
26 | value = (T) ((HibernateProxy) value).getHibernateLazyInitializer().getImplementation(); |
31 | @SuppressWarnings ( "unchecked" ) |
32 | @Transactional (propagation=Propagation.REQUIRED, readOnly= true ) |
33 | public List<T> getAll() { |
34 | Criteria crit = getSession().createCriteria(type); |
38 | public void createOrUpdate(T o) { |
39 | if (o instanceof AbstractPersistentObject) { |
40 | if (((AbstractPersistentObject) o).isCreation()) { |
41 | getSession().saveOrUpdate(o); |
43 | getSession().merge(o); |
46 | throw new RuntimeException( "this method support only AbstractPersistentObject" ); |
51 | public void update(T o) { |
52 | getSession().update(o); |
55 | public void delete(T o) { |
56 | getSession().delete(o); |
Specific DAO
Here, an example using the below class and interface in a specific DAO:
-
Example of a specific DAO interface that would can call the generic methods:
1 | public interface ChapterDao extends GenericDao<Chapter, String> { |
4 | * Find the chapter by number. |
6 | public List<Chapter> findByNumber(String number) throws DataAccessException; |
- Then, its implementation which contains the generic methods and the specific method ‘findByNumber’:
01 | @Repository ( "chapterDao" ) |
03 | public class ChapterDaoHibernateImpl extends GenericDaoImpl<Chapter, String> implements ChapterDao { |
06 | public ChapterDaoHibernateImpl( @Qualifier ( "sessionFactory" ) SessionFactory sessionFactory) { |
07 | super (sessionFactory, Chapter. class ); |
11 | * Find the chapter by number. |
13 | @SuppressWarnings ( "unchecked" ) |
15 | @Transactional (propagation=Propagation.MANDATORY, readOnly= true ) |
16 | public List<Chapter> findByNumber(String number) throws DataAccessException { |
17 | StringBuffer hql = new StringBuffer( "select chapter from Chapter chapter " ); |
18 | hql.append( " where chapter.number=:number " ); |
19 | Query query = getSession().createQuery(hql.toString()); |
21 | query.setString( "number" , number); |
22 | List<Chapter> chapters = query.list(); |
These classes and interfaces are built around the best pratices defined in the section HashCode, Equals methods and ORM layer of the post Java/Hibernate: HashCode, Equals methods.
So, our POJO must extend an abstract class with the HashCode, Equals methods overridden in order to compare correctly two objects and containing also a ‘id’ and ‘version’ attributes:
02 | * AbstractPersistentObject |
03 | * @author Huseyin OZVEREN |
05 | public abstract class AbstractPersistentObject { |
06 | private String id = IdGenerator.createId(); |
08 | private Integer version = null ; |
11 | public String getId() { |
15 | public void setId(String value) { |
19 | public Integer getVersion() { |
23 | public void setVersion(Integer value) { |
27 | public boolean equals(Object o) { |
28 | if ( this == o) return true ; |
29 | if (o == null || !(o instanceof AbstractPersistentObject )) { |
33 | AbstractPersistentObject other = (AbstractPersistentObject ) o; |
36 | if (id == null ) return false ; |
39 | return id.equals(other.getId()); |
42 | public int hashCode() { |
46 | return super .hashCode(); |
50 | public String toString() { |
51 | return this .getClass().getName() |
55 | public boolean isCreation() { |
56 | return version == null ; |
59 | public void regenerateId() { |
60 | id = IdGenerator.createId(); |
64 | public AbstractPersistentObject() { |
The IdGenerator generates an unique Id:
1 | public class IdGenerator { |
3 | public static String createId() { |
4 | UUID uuid = java.util.UUID.randomUUID(); |
5 | return uuid.toString(); |
Example of business classes ‘Book’ and ‘Chapter’ in ORM layer:
01 | public class Book extends AbstractPersistentObject { |
05 | private String category = null ; |
07 | private boolean previouslyPublished = false ; |
08 | private String isbn10; |
09 | private String isbn13; |
10 | private Set<Author> authors = new HashSet<Author>(); |
11 | private double price = 0 ; |
12 | private Language language = null ; |
13 | private Set<Chapter> chapters = new HashSet<Chapter>(); |
01 | public class Chapter extends AbstractPersistentObject { |
04 | private Book book = null ; |
05 | private Calendar creationDate = null ; |
06 | private Calendar modifDate = null ; |
07 | private String title = null ; |
08 | private int number = 0 ; |
09 | private String content = null ; |
12 | public void setBook(Book book) { |
16 | public Book getBook() { |
17 | book = ORMUtils.initializeAndUnproxy(book); |
The source code of the GenericDaoImpl and GenericDao interface are in the ZIP file attachement.
This project needs the following librairies commons-beanutils-1.7.0.jar, commons-lang-2.4.jar, commons-logging-1.1.1.jar, hibernate-core-3.3.1.GA.jar, junit-4.1.jar and spring-2.5.5.jar.
Conclusion
A good practice in programming n-tier is to group queries into the service layer. The use of a generic DAO will reduce the number of code’s lines because all standard access methods are available in one class. So, the service layer will contains only the complex methods. More, all queries with HQL queries will be grouped in a single service object that corresponds to a domain object representing a module.
Download: test_ORMTools.zip
Best regards,
Related
nice post. keep going!
I needed to thank you for this wonderful read!! I definitely enjoyed every bit of it.
I have got you saved as a favorite to check out new things you post