Monday, October 24, 2005

Hibernate Generic Dao

Christian Bauer blogged sometime before about a Generic Hibernate Dao pattern with JDK 5. This pattern has the advantage of simplifying the dao construction, It also allows for direct access to the underlying Hibernate session witch makes it possible to use the Hibernate powerfull API for data manipulation. The only issue I can think of, as a Spring Framework user, is intergation with Spring Framework declarative services, mainly transaction demarcation.

I updated Christian code to make the Generic Dao easily advisable by Spring Framework ProxyFactories to provide transactions management and other enterprise services.

/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.adam.dao.hibernate;

import java.io.Serializable;
import java.util.List;

import org.adam.dao.GenericDao;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.util.Assert;

/**
* GenericHibernateDao that should be extended by HibernateDaos.
* @author Omar Irbouh
* @since 2005.09.12
*/
public abstract class GenericHibernateDao implements GenericDao, InitializingBean {

protected transient Log logger = LogFactory.getLog(getClass());

private Class persistentClass;
private SessionFactory sessionFactory;

public GenericHibernateDao() {
}

public GenericHibernateDao(SessionFactory sessionFactory, Class persistentClass) {
this.persistentClass = persistentClass;
this.sessionFactory = sessionFactory;
}

protected SessionFactory getSessionFactory() {
return sessionFactory;
}

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

private Class getPersistentClass() {
return persistentClass;
}

public void setPersistentClass(Class persistentClass) {
this.persistentClass = persistentClass;
}

public void afterPropertiesSet() throws Exception {
Assert.notNull(getSessionFactory(), "sessionFactory is required");
Assert.notNull(getPersistentClass(), "persistentClass is required");
}

@SuppressWarnings({"unchecked"})
public T findById(ID id, boolean lock) throws DataAccessException {
return (T) getSession().load(getPersistentClass(), id, (lock) ? LockMode.UPGRADE : LockMode.NONE);
}

public List findByExample(T exampleInstance) throws DataAccessException {
return findByCriteria(Example.create(exampleInstance));
}

@SuppressWarnings({"unchecked"})
public T store(T entity) throws DataAccessException {
return (T) getSession().merge(entity);
}

public void delete(T entity) throws DataAccessException {
getSession().delete(entity);
}

@SuppressWarnings({"unchecked"})
public List findAll() throws DataAccessException {
return findByCriteria();
}

@SuppressWarnings({"unchecked"})
protected List findByCriteria(Criterion... criterion) {
Criteria criteria = getSession().createCriteria(getPersistentClass());
for (Criterion c : criterion) {
criteria.add(c);
}
return criteria.list();
}

protected Session getSession() {
return SessionFactoryUtils.getSession(sessionFactory, true);
}

}

This abstract class can be subclassed as follows:

/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.adam.dao.hibernate;

import org.adam.dao.RoleDao;
import org.adam.model.Role;
import org.hibernate.Query;
import org.springframework.dao.DataAccessException;

/**
* Hibernate implmentation of the RoleDao business interface.
* @author Omar Irbouh
* @since 2005.08.29
*/
public class HibernateRoleDao extends GenericHibernateDao implements RoleDao {

/**
* Hibernate named query used to retrieve a Role by its name.
*/
private static final String QUERY_ROLE_BY_NAME = "role.by.name";

public Role findByName(final String name) throws DataAccessException {
Query query = getSession().getNamedQuery(QUERY_ROLE_BY_NAME);
query.setParameter("name", name);
return (Role) query.uniqueResult();
}

}

GenericHibernateDao delegates to SessionFactoryUtils for Hibernate session creation / synchronisation.

No comments: