Hibernate with JPA Annotations and Guice

05/01/2010

In this tutorial, I use the H2 database, which you can utilize by downloading the jar or you can replace with your own DB.

First off, you need to create a persistence.xml in a folder named META-INF at the root of your classpath. For example, if you’re using Maven you can create src/main/java/META-INF/persistence.xml. It lists all the classes you want Hibernate to persist and any other Hibernate properties you might want to specify. I also define Hibernate properties later on in the tutorial when creating the EntityManagerFactory.

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
  <persistence-unit name="db-manager">
    <class>com.benmccann.db.ExamplePersistedClass</class>
    <properties>
      <!-- Disable the second-level cache  -->
      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>

      <!-- Default is false for backwards compatibility.  Should be used on all new projects -->
      <property name="hibernate.id.new_generator_mappings" value="true"/>
    </properties>
  </persistence-unit>
</persistence>

We listed the class com.benmccann.db.ExamplePersistedClass as being the only persisted class, so now we’ll go ahead and create it. Note that you need a no-argument constructor. Fields in your bean will be persisted unless annotated with @Transient. More info about persisted classes is available in the Hibernate documentation.

package com.benmccann.db;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class ExamplePersistedClass {

  @Id
  @GeneratedValue
  private Long id;
  
  private String otherField;

  public ExamplePersistedClass() {}

  public void setId(Long id) {
    this.id = id;
  }

  public Long getId() {
    return id;
  }

  public void setOtherField(String otherField) {
    this.otherField = otherField;
  }

  public String getOtherField() {
    return otherField;
  }

}

And we’ll create a DAO for it:

package com.benmccann.db;

import javax.persistence.EntityManager;

public class ExamplePersistedClassDao {

  protected EntityManager entityManager;
  
  @Inject
  public ExamplePersistedClassDao(EntityManager entityManager) {
    this.entityManager = entityManager;
  }
  
  public void saveInNewTransaction(ExamplePersistedClass object) {
    entityManager.getTransaction().begin();
    save(object);
    entityManager.getTransaction().commit();
  }
  
  public void save(ExamplePersistedClass object) {
    entityManager.persist(object);
  }
  
  public ExamplePersistedClass getByOtherField(String otherField) {
    return (ExamplePersistedClass) entityManager
        .createQuery("select e from ExamplePersistedClass e where e.otherField=:otherField")
        .setParameter("otherField", otherField)
        .getSingleResult();
  }

}

And finally, we’ll create a Guice module to define the injection. Note that EntityManagerFactory is thread-safe while EntityManager is not. I use ThreadLocal storage here in order to have one entity manager per thread. When creating the EntityManagerFactory notice that I use the same “db-manager” string that is defined in the persistence.xml file. Also, I defined most of my Hibernate properties here rather than in the persistence.xml file to demonstrate how you can alter the values of these properties. For example, when writing tests it could be very helpful to override the connection string to point to a local test database.

package com.benmccann.db;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;

/**
 * @author Ben McCann (benmccann.com)
 */
public class DbModule extends AbstractModule {

  private static final ThreadLocal<EntityManager> ENTITY_MANAGER_CACHE
      = new ThreadLocal<EntityManager>();

  public void configure() {
  }

  @Provides @Singleton
  public EntityManagerFactory provideEntityManagerFactory() {
    Map<String, String> properties = new HashMap<String, String>();
    properties.put("hibernate.connection.driver_class", "org.h2.Driver");
    properties.put("hibernate.connection.url", "jdbc:h2:test");
    properties.put("hibernate.connection.username", "sa");
    properties.put("hibernate.connection.password", "");
    properties.put("hibernate.connection.pool_size", "1");
    properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
    properties.put("hibernate.hbm2ddl.auto", "create");
    return Persistence.createEntityManagerFactory("db-manager", properties);
  }
  
  @Provides
  public EntityManager provideEntityManager(EntityManagerFactory entityManagerFactory) {
    EntityManager entityManager = ENTITY_MANAGER_CACHE.get();
    if (entityManager == null) {
      ENTITY_MANAGER_CACHE.set(entityManager = entityManagerFactory.createEntityManager());
    }
    return entityManager;
  }

}

Now we can run our code:

package com.benmccann.db;

import java.sql.SQLException;
import java.util.Date;

import org.junit.Assert;
import org.junit.Test;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.benmccann.db.DbModule;
import com.benmccann.db.ExamplePersistedClass;
import com.benmccann.db.ExamplePersistedClassDao;

public class H2DBTest {

  @Test
  public void testDb() throws SQLException {
    Injector injector = Guice.createInjector(new DbModule());
    ExamplePersistedClassDao examplePersistedClassDao = injector.getInstance(ExamplePersistedClassDao.class);   

    ExamplePersistedClass example = new ExamplePersistedClass();
    example.setOtherField("hello world");
    examplePersistedClassDao .saveInNewTransaction(quote);

    ExamplePersistedClass retrieved = examplePersistedClassDao.getByOtherField("hello world");

    Assert.assertEquals(example.getId(), retrieved.getId());
    Assert.assertEquals(example.getOtherField(), retrieved.getOtherField());
  }

}