RSS Feed for This PostCurrent Article

Design of a Java Application Framework Part 2 – DAO Layer using Hibernate

This is the sequel of my previous post on the AppFuse source code, a good MVC framework. Thanks to Matt Raible and the team for this wonderful framework.

By reading the code, I can understand the framework better in order to use it correctly.

For AppFuse, for the data access layer you can use Hibernate, iBATIS or JPA. Here I am going through the Hibernate code.

All the DAO interface shall implement the GenericDao interface.

 

/**

 * Generic DAO (Data Access Object) with common methods to CRUD POJOs.

 *

 * <p>Extend this interface if you want typesafe (no casting necessary) DAO's for your

 * domain objects.

 *

 * @param <T> a type variable

 * @param <PK> the primary key for that type

 */

public interface GenericDao <T, PK extends Serializable> {

 

    /**

     * Generic method used to get all objects of a particular type. This

     * is the same as lookup up all rows in a table.

     * @return List of populated objects

     */

    List<T> getAll();

 

    /**

     * Generic method to get an object based on class and identifier. An

     * ObjectRetrievalFailureException Runtime Exception is thrown if

     * nothing is found.

     *

     * @param id the identifier (primary key) of the object to get

     * @return a populated object

     * @see org.springframework.orm.ObjectRetrievalFailureException

     */

    T get(PK id);

 

    /**

     * Checks for existence of an object of type T using the id arg.

     * @param id the id of the entity

     * @return - true if it exists, false if it doesn't

     */

    boolean exists(PK id);

 

    /**

     * Generic method to save an object - handles both update and insert.

     * @param object the object to save

     * @return the persisted object

     */

    T save(T object);

 

    /**

     * Generic method to delete an object based on class and id

     * @param id the identifier (primary key) of the object to remove

     */

    void remove(PK id);

    

    /**

     * Gets all records without duplicates.

     * <p>Note that if you use this method, it is imperative that your model

     * classes correctly implement the hashcode/equals methods</p>

     * @return List of populated objects

     */

    List<T> getAllDistinct();

    

 

    /**

     * Find a list of records by using a named query

     * @param queryName query name of the named query

     * @param queryParams a map of the query names and the values

     * @return a list of the records found

     */

    List<T> findByNamedQuery(String queryName, Map<String, Object> queryParams);

}

In this interface, common CRUD methods are defined. The interface accepts 2 parameters, which is the type variable and the PK for that type.

And GenericDaoHibernate class implements GenericDao interface

 

/**

 * This class serves as the Base class for all other DAOs - namely to hold

 * common CRUD methods that they might all use. You should only need to extend

 * this class when your require custom CRUD logic.

 *

 * <p>To register this class in your Spring context file, use the following XML.

 * <pre>

 *      &lt;bean id="fooDao" class="org.appfuse.dao.hibernate.GenericDaoHibernate"&gt;

 *          &lt;constructor-arg value="org.appfuse.model.Foo"/&gt;

 *          &lt;property name="sessionFactory" ref="sessionFactory"/&gt;

 *      &lt;/bean&gt;

 * </pre>

 * @param <T> a type variable

 * @param <PK> the primary key for that type

 */

public class GenericDaoHibernate<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> {

    /**

     * Log variable for all child classes. Uses LogFactory.getLog(getClass()) from Commons Logging

     */

    protected final Log log = LogFactory.getLog(getClass());

    private Class<T> persistentClass;

 

    /**

     * Constructor that takes in a class to see which type of entity to persist

     * @param persistentClass the class type you'd like to persist

     */

    public GenericDaoHibernate(final Class<T> persistentClass) {

        this.persistentClass = persistentClass;

    }

 

    /**

     * {@inheritDoc}

     */

    @SuppressWarnings("unchecked")

    public List<T> getAll() {

        return super.getHibernateTemplate().loadAll(this.persistentClass);

    }

    

    /**

     * {@inheritDoc}

     */

    @SuppressWarnings("unchecked")

    public List<T> getAllDistinct() {

        Collection result = new LinkedHashSet(getAll());

        return new ArrayList(result);

    }

    

    /**

     * {@inheritDoc}

     */

    @SuppressWarnings("unchecked")

    public T get(PK id) {

        T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);

 

        if (entity == null) {

            log.warn("Uh oh, '" + this.persistentClass + "' object with id '" + id + "' not found...");

            throw new ObjectRetrievalFailureException(this.persistentClass, id);

        }

 

        return entity;

    }

 

    /**

     * {@inheritDoc}

     */

    @SuppressWarnings("unchecked")

    public boolean exists(PK id) {

        T entity = (T) super.getHibernateTemplate().get(this.persistentClass, id);

        return entity != null;

    }

 

    /**

     * {@inheritDoc}

     */

    @SuppressWarnings("unchecked")

    public T save(T object) {

        return (T) super.getHibernateTemplate().merge(object);

    }

 

    /**

     * {@inheritDoc}

     */

    public void remove(PK id) {

        super.getHibernateTemplate().delete(this.get(id));

    }

    

   /** 

    * {@inheritDoc}

    */

   @SuppressWarnings("unchecked")

   public List<T> findByNamedQuery(

       String queryName, 

       Map<String, Object> queryParams) {

       String []params = new String[queryParams.size()];

       Object []values = new Object[queryParams.size()];

       int index = 0;

       Iterator<String> i = queryParams.keySet().iterator();

       while (i.hasNext()) {

           String key = i.next();

           params[index] = key;

           values[index++] = queryParams.get(key);

       }

       return getHibernateTemplate().findByNamedQueryAndNamedParam(

           queryName, 

           params, 

           values);

   }

}

 

Here is the example of the UserDao interface

 

/**

 * User Data Access Object (GenericDao) interface.

 *

 */

public interface UserDao extends GenericDao<User, Long> {

 

    /**

     * Gets users information based on login name.

     * @param username the user's username

     * @return userDetails populated userDetails object

     * @throws org.springframework.security.userdetails.UsernameNotFoundException thrown when user not found in database

     */

    @Transactional

    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;

 

    /**

     * Gets a list of users ordered by the uppercase version of their username.

     *

     * @return List populated list of users

     */

    List<User> getUsers();

 

    /**

     * Saves a user's information.

     * @param user the object to be saved

     * @return the persisted User object

     */

    User saveUser(User user);

 

    /**

     * Retrieves the password in DB for a user

     * @param username the user's username

     * @return the password in DB, if the user is already persisted

     */

    @Transactional(propagation = Propagation.NOT_SUPPORTED)

    String getUserPassword(String username);

    

}

Note that Spring Framework is used for security and transactional control here.

And the UserDaoHibernate class shall extends GenericDaoHibernate and implements UserDao.

/**

 * This class interacts with Spring's HibernateTemplate to save/delete and

 * retrieve User objects.

 *

 */

public class UserDaoHibernate extends GenericDaoHibernate<User, Long> implements UserDao, UserDetailsService {

 

    /**

     * Constructor that sets the entity to User.class.

     */

    public UserDaoHibernate() {

        super(User.class);

    }

 

    /**

     * {@inheritDoc}

     */

    @SuppressWarnings("unchecked")

    public List<User> getUsers() {

        return getHibernateTemplate().find("from User u order by upper(u.username)");

    }

 

    /**

     * {@inheritDoc}

     */

    public User saveUser(User user) {

        log.debug("user's id: " + user.getId());

        getHibernateTemplate().saveOrUpdate(user);

        // necessary to throw a DataIntegrityViolation and catch it in UserManager

        getHibernateTemplate().flush();

        return user;

    }

 

    /**

     * Overridden simply to call the saveUser method. This is happenening 

     * because saveUser flushes the session and saveObject of BaseDaoHibernate 

     * does not.

     *

     * @param user the user to save

     * @return the modified user (with a primary key set if they're new)

     */

    @Override

    public User save(User user) {

        return this.saveUser(user);

    }

 

    /** 

     * {@inheritDoc}

    */

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        List users = getHibernateTemplate().find("from User where username=?", username);

        if (users == null || users.isEmpty()) {

            throw new UsernameNotFoundException("user '" + username + "' not found...");

        } else {

            return (UserDetails) users.get(0);

        }

    }

 

    /** 

     * {@inheritDoc}

    */

    public String getUserPassword(String username) {

        SimpleJdbcTemplate jdbcTemplate =

                new SimpleJdbcTemplate(SessionFactoryUtils.getDataSource(getSessionFactory()));

        Table table = AnnotationUtils.findAnnotation(User.class, Table.class);

        return jdbcTemplate.queryForObject(

                "select password from " + table.name() + " where username=?", String.class, username);

 

    }

    

}

Spring Framework is used heavily here since it has good support for Hibernate. Emm…. is there any other choice?


Trackback URL


RSS Feed for This Post1 Comment(s)

  1. vojtech.szocs | Mar 20, 2009 | Reply

    Hi, we have released an OpenSource project that goes far beyond a generic CRUD-like DAO.

    You can find it here: http://opensource.anasoft.com/daofusion-site/ or http://opensource.anasoft.sk/daofusion-site/

    DAO Fusion is a lightweight yet comprehensive tool for building reliable, maintainable and testable DAO layers using JPA / Hibernate.

    It covers five main areas related to DAO layer development:

    – persistent entity model
    – standard persistent entity DAO interfaces / abstract implementations
    – persistent entity criteria API with advanced filtering, sorting and paging capabilities
    – criteria transfer object (CTO) pattern that allows clients to specify entity criteria easily (this is especially useful for grid-like operations)
    – integration test support using JUnit / Spring TestContext framework (core DAO functionality is integration-tested out-of-the-box for many popular databases)

    The project is open to everyone interested in JPA, Hibernate and related technologies.

    Cheers,
    Vojtech

Sorry, comments for this entry are closed at this time.