Getting Started with Hibernate 3 and NetBeans 6.5 Beta Part 3

Welcome back, this article is a continuation from parts 1 and 2, which covered setting up Hibernate in Netbeans as well as creating using Hibernate commands in Data Access Objects to interact with the database. In this part, we’re going to accomplish two things:

  1. Create a J2EE filter that manages Hibernate sessions
  2. Create relationship mappings between entities

What is a Filter and Why?

Filters are a piece of J2EE technology that wraps around requests that are sent by the user. This allows you to intercept requests, blocking them or to do things. Many frameworks use filters to accomplish this like Sitemesh and Struts 2.

For our purposes, we find that a lot of Hibernate boilerplate code resides in the DAO. This isn’t that bad, because the DAO is in charge of this anyway. However, since Hibernate already manages our database connection sessions for us, this is just repetitive. It’s a good candidate to be filtered out into a filter. Pun intended.

The Hibernate Session Filter

Firstly, create a java class HibernateSessionFilter.java in your data package (or wherever you want to) and paste this codes inside:


package data;

import java.io.*;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.hibernate.SessionFactory;
import org.hibernate.Session;

public class HibernateSessionFilter implements Filter {

    private FilterConfig filterConfig = null;

    public HibernateSessionFilter() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    throws IOException, ServletException {
        SessionFactory factory = HibernateUtil.getSessionFactory();
        Session session = factory.getCurrentSession();

        try {
            session.beginTransaction();
            chain.doFilter(request, response);
            session.getTransaction().commit();

        } catch (Throwable e) {
            if (session.getTransaction().isActive()) {
                session.getTransaction().rollback();
            }

            throw new ServletException(e);
        }
    }

    public void destroy() { 
    }

    public void init(FilterConfig filterConfig) { 
        this.filterConfig = filterConfig;
        if (filterConfig == null) {
            filterConfig.getServletContext().log("HibernateSessionFilter: Initializing filter failed");
        }
    }
}

You will be able to recognize some of the codes inside the doFilter method as the boilerplate code that we had to have in our DAO. By having this file, we will be able to skip all this.

In between the lines where we begin a transaction and commit it, we see that we are executing the request by passing it along the chain. This is because in J2EE web applications, there can be more than one filter, and we have to play nice with the next filter.

Adding the Filter to the Application

Before we’re done with this section, we need to let the application know about our newly created filter. To do so, visit the web.xml and add in these lines of codes inside the web-app element:


<filter>
    <filter-name>HibernateSessionFilter</filter-name>
    <filter-class>data.HibernateSessionFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HibernateSessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Cleaning up the DAO

Now, instead of the DAO with all the boilerplate code, you can do this instead (with some bonus methods thrown in):


package data;

import java.util.LinkedHashSet;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.Criteria;
import java.util.Set;

public abstract class GenericDao {
    protected Class persistedClass;
    protected Session session;

    public GenericDao(Class persistedClass) {
        SessionFactory factory = HibernateUtil.getSessionFactory();
        this.session = factory.getCurrentSession();
        this.persistedClass = persistedClass;
    }

    public Object findById(int id) {
        Object object = (Object) session.get(persistedClass, id);
        return object;
    }

    public void save(Object object) {
        session.save(object);
    }

    public void persist(Object object) {
        session.persist(object);
    }

    public void saveOrUpdate(Object object) {
        session.saveOrUpdate(object);
    }

    public void delete(Object object) {
        session.delete(object);
    }

    public Set findAll() {
        Criteria criteria = session.createCriteria(persistedClass);

        Set set = new LinkedHashSet();
        set.addAll(criteria.list());   
        return set; 
    }

}

Limitations of the Hibernate Session Filter

This is not meant to be production ready, or even suited to professional development. It is far too simplistic and a lot of considerations have been ignored. A somewhat more advanced implementation at can be found here.

I haven’t tested it out yet, but it seems to have tighter controls around sessions as well as a more robust handling. With the implementation we created in this guide, I sometimes encounter closed sessions that do not reopen on my development machine after hibernating my laptop. Fixing it requires a restart of the server, but so far, there are no problems once deployed to a production server. Perhaps as an exercise, you can try out the above implementation.

Hibernate Relationships

In part 1, we created 3 entity classes: User, Room and Bookings. Here is the logical diagram that we’ll be working with:

For our SimpleHibernate project, we’ll be dealing with two one-to-many relationships. What we want to accomplish is that we can get a list Booking objects from a User or Room. In addition, we want to be able to access who made the booking and for which room in the Booking object. Thus we want bidirectional mappings to and from each of the classes.

Change the classes first

It is easier to see what we’re doing if we create what we want the final result to look like first. In the entity classes, let us add new instance variables that we can later map with Hibernate. This is as simple as well, adding instance variables and generating getters and setters.

Let’s open up User.java first and add this line to the instance variables.


private Set bookings;

In NetBeans, you can type ctrl-space when your cursor is right after Set and it will automatically import the class for you. In addition, we will want to make NetBeans generate the getters/setters for us, so move your cursor down where you want to create these two methods, right click and select Insert Code… or hit the alt-insert shortcut. Follow the next few steps and you’re done.

Mapping with Hibernate

Now that we know what we want the class to do; get a Set of Booking objects. We need to tell Hibernate how to do just that. Open up User.hbm.xml and paste the following into the class element:


<set name="bookings">
    <key column="user_id"/>
    <one-to-many class="entities.Booking"/>
</set>

Here, name refers to the instance variable in the User class, user_id refers to the foreign key field in the Booking table. The one-to-many element tells Hibernate which object to create in the Set.

Making it Bidirectional

In Booking.java we will want to have an object of type User preferably accessed by the method getUser(). Instead, we now have userId of type integer and the accessor methods. Delete them all and we’ll add in our own instance variable like so:


private User user;

Generate the accessor methods to for the new variable. You will notice that we have a problem with the constructor not being able to find userId. Delete it from the parameter list as well as the line where the assignment takes place.

Things should compile now, but we still have to do the Hibernate mappings so head on over to the hbm file for bookings.

Replace these lines of code:


<property name="userId" type="int">
    <column name="user_id" not-null="true"/>
</property>

with:


<many-to-one class="entities.User" column="user_id" fetch="join" lazy="false" name="user"/>

Not so difficult huh? Notice that we now use a many-to-one mapping instead of a one-to-many. The rest are self explanatory, but if you want a more complete look at the various settings you can use, take a peek at this cheat sheet.

Conclusion

This marks the end of this series; hopefully it has given you a better idea of how you can use Hibernate at a beginner’s level. So where to now? Here is a series of Hibernate tutorials that helped me learn the framework. It is very simple and the explanations are short and sweet.