Testable HibernateUtil

I have seen many projects using the HibernateUtil which was proposed in the docs.

This class is not really testable because for example you cannot configure that it should use the test database. Normally I would suggest you using Spring and avoiding the singleton pattern, but there is a also a simple work around: introduce a setConfiguration and you will have a better HibernateUtil class:

public final class HibernateUtil {
    private static final Class<?> mappedClasses[] = new Class<?>[] { Bla1.class, Bla2.class };
    private static Configuration cfg;
    private static SessionFactory sessionFactory;
    private static final Logger log = Logger.getLogger(HibernateUtil.class);

    /** Returns the configuration object. configure() was already called.  */
    public static synchronized Configuration getConfiguration() {
        if (cfg == null) {
            log.debug("Configuring from annotations");
            AnnotationConfiguration annoCfg = new AnnotationConfiguration();
            for (Class<?> c : mappedClasses) {
                annoCfg = annoCfg.addAnnotatedClass(c);
            }
            cfg = annoCfg.configure();
        }
        return cfg;
    }

    public static void setConfiguration(Configuration config) {
        cfg = config;
    }

    /** Drop and recreate the schema */
    public static void recreateSchema() {
        SchemaExport schemaTool = new SchemaExport(getConfiguration());
        schemaTool.drop(true, true);
        schemaTool.create(true, true);
    }

    /** This method returns a session-factory. */
    public static synchronized SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            sessionFactory = getConfiguration().buildSessionFactory();
        }
        return sessionFactory;
    }
}

Now you can use the following junit (v4) test as a base class for all test classes that will use HibernateUtil:

public class HibernateTestCase {
 protected Logger log = Logger.getLogger(HibernateTestCase.class);
 private Session session;
 private static SessionFactory sessionFactory;

 static {
    // H2 database works only if Bla.id has one of the following annotations:
    // @GeneratedValue(strategy = GenerationType.SEQUENCE) or GenerationType.TABLE
    HibernateUtil.setConfiguration(HibernateUtil.getConfiguration()
     .setProperty("hibernate.connection.driver_class", "org.h2.Driver")
     .setProperty("hibernate.connection.url", "jdbc:h2:mem:bla-test-db2")
     .setProperty("hibernate.connection.driver_class", "org.h2.Driver")
     .setProperty("hibernate.connection.username", "sa")
     .setProperty("hibernate.connection.password", "")
     .setProperty("hibernate.default_schema", "MY_SCHEMA")
     .setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
     .setProperty("current_session_context_class", "thread")
     .setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider")
     .setProperty("hibernate.show_sql", "true"));

  sessionFactory = HibernateUtil.getSessionFactory();
  Session session = sessionFactory.getCurrentSession();

  assertFalse(HibernateUtil.getConfiguration().getProperty("hibernate.connection.driver_class").equals(
				"specify here you driver used in production"));
  // We only need to create the schema for in-memory databases and for newly created databases!
  boolean freshDatabase = true;
  if(freshDatabase) {
  	session.beginTransaction();
  	String CREATE_SCHEMA = "create schema MY_SCHEMA";
  	session.createSQLQuery(CREATE_SCHEMA).executeUpdate();
  	session.getTransaction().commit();
  	session = sessionFactory.getCurrentSession();
  }

  session.beginTransaction();
  HibernateUtil.recreateSchema();

  if (session.isOpen()) {
  	session.close();
  }
 }

 @Before
 public void setUp() throws Exception {
  session = sessionFactory.getCurrentSession();
  session.beginTransaction();
 }

 @After
 public void tearDown() throws Exception {
  session.getTransaction().rollback();
  if (session.isOpen()) {
  	session.close();
  }
 }

 public Session getSession() {
  return session;
 }

 public void commitAndCreateNewSession() {
  session.getTransaction().commit();
  session = sessionFactory.getCurrentSession();
  session.beginTransaction();
 }
}

2 thoughts on “Testable HibernateUtil

  1. When I try to use your example, I get
    org.hibernate.HibernateException: No CurrentSessionContext configured!
    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:572)

    It seem to happen right after:
    session = sessionFactory.getCurrentSession();

    Any idea?

  2. I think I found the issue. It was staring me in the face. I added the following to HibernateUtil.setConfiguration

    .setProperty(“hibernate.current_session_context_class”, “thread”));

Comments are closed.