Adding JPA/Hibernate into the CDI and Wicket Mix

Posted by on Nov 21, 2011 in Full Stack Implementation, Software Engineering | 5 comments

In this article we are going to build a simple solution for integrating JPA/Hibernate first with CDI and later with Wicket. Instead of starting from scratch we are going to use the project created in the previous article ( Integrating CDI Into Wicket ) as a base. If you are not familiar with it have a quick readthrough.

Preparing Hibernate

Before we can integrate Hibernate we need to add it to our project’s pom:

<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate-entitymanager</artifactId>
  <version>3.6.8.Final</version>
</dependency>

Lets also add an embeddable sql database so we can have some in-memory throw-away instance we can play with. We are going to use H2:

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>1.3.161</version>
  <scope>test</scope>
</dependency>

In order to bootstrap JPA we need a persistence unit descriptor:

src/main/resources/META-INF/persistence.xml

<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="cdidemo"> <!--1-->
    <properties>
      <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/> <!--2-->
      <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:cdidemo"/>
      <property name="javax.persistence.jdbc.user" value="sa"/>
      <property name="javax.persistence.jdbc.password" value=""/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <!--3-->
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/> <!--4-->
    </properties>
  </persistence-unit>
</persistence>

  1. Name our persistence unit so we can refer to it from code
  2. Setup jdbc to point at an in-memory instance of the database
  3. Tell Hibernate we are using H2 so it can generate correct sql variants
  4. Since we are using an in-memory database instance which will start blank every time we tell Hibernate to create the sql schema for us on startup

Bootstrapping JPA

We are now ready to bootstrap JPA. The process starts with creating an EntityManagerFactory for our persistence unit. We want to only have one instance of this factory per application so it needs to live in the application scope. Since Hibernate’s implementation of this interface does not have any CDI annotations and Hibernate’s jar does not have a beans.xml file we cannot simply @Inject EntityManagerFactory instances yet. To enable the injection we need to create a factory that will create the EntityManagerFactory instance for us whenever something needs it, and dispose of it when the application shuts down. A basic factory for CDI beans uses a combination of producer and disposer methods. We implement the factory like this:

public class EntityManagerFactoryProducer {
 
  @Produces //1
  @ApplicationScoped //2
  public EntityManagerFactory create() {
    return Persistence.createEntityManagerFactory("cdidemo"); //3
  }
 
  public void destroy(@Disposes EntityManagerFactory factory) { //4
    factory.close(); //5
  }
}

  1. Marks create() as a producer methods using its return type to determine what type of beans it can produce.
  2. The scope of the produced bean, in our case since we want to have only one EntityManagerFactory we mark it as application-scoped
  3. Creates the EntityManagerFactory instance for our persistence unit
  4. The @Disposes annotation marks this method as a disposer for any bean of EntityManagerFactory type
  5. Dispose of the EntityManagerFactory instance by closing it

Now we can @Inject EntityManagerFactory instances as a dependency into other beans. However, what we are really after here is being able to @Inject EntityManager instances, so we create another factory:

public class EntityManagerProducer {
 
  @Inject EntityManagerFactory emf; //1
 
  @Produces @ConversationScoped //2
  public EntityManager create() {
    return emf.createEntityManager();
  }
 
  public void destroy(@Disposes EntityManager em) {
    em.close();
  }
}

  1. We need the EntityManagerFactory instance, so we inject it
  2. We are going to keep our EntityManager instances in the conversation scope. For the purposes of this article think of the conversation scope as equivalent to request cope, meaning each request will get a fresh instance of EntityManager that will be closed by our disposer method at the end of the request

At this point we have the minimum possible integration of Hibernate and CDI. There are a couple of caveats which we will fix in a later post:

  • No declarative transaction management such as @Transactional or another mechanism
  • No way to use EntityManager outside a web-thread because worker threads do not have a conversation

To test it out lets create a simple entity:

@Entity
public class Employee {
 
  @GeneratedValue @Id Long id;
  String firstName;
  String lastName;
  String email;
}

And now we are going to modify our HomePage to test JPA by displaying the count of Employees in our database:

public class HomePage extends WebPage {
 
  public HomePage() {
    add(new Label("count", new LoadableDetachableModel() {
      {
        CdiContainer.get().getNonContextualManager().inject(this); //1
      }
 
      @Inject EntityManager em; //2
 
      @Override protected Long load() {
        return (Long) em.createQuery("SELECT COUNT(*) FROM Employee")
          .getSingleResult(); //3
      }
    }));
  }
}

  1. Because IModel instances are not injected automatically we have to do the injection ourselves
  2. Inject EntityManager so we can query
  3. Run a simple count query to test if the integration works

Next we will take a look at how to better integrate JPA with Wicket

Adding Wicket Integration

There are two main activities web applications do with entities: hold references to them and list them. Typical web applications hold references by passing around entity ids, in Wicket we use models. I have written how to create a good model to hold entities here: Building a smart EntityModel and expanded on it in my book: Apache Wicket Cookbook, so I will not spend a lot of time on it here. Lets quickly look over a simple one that will be good enough for now:

public class EntityModel&lt;T&gt; implements IModel&lt;T&gt; {
 
  @Inject private EntityManager em; //1
 
  private Object id; //2
  private Class type;
 
  private transient T entity; //3
 
  public EntityModel(T entity) {
    CdiContainer.get().getNonContextualManager().inject(this); //4
    setObject(entity);
  }
 
  public T getObject() {
    if (entity == null) { entity = (T) em.find(type, id); } //5
    return entity;
  }
 
  public final void setObject(T other) {
    type = other.getClass();
    id = em.getEntityManagerFactory()
      .getPersistenceUnitUtil().getIdentifier(other); //6
    entity = other;
  }
 
  public void detach() {
    entity = null;
  } //5
}

  1. Inject the entity manager so we can load entities
  2. In order to load an entity we need to know its id and type
  3. Cache for the entity, so we load at most once per request
  4. Model instances are not injected automatically, so inject this instance
  5. Lazy-load the entity if we dont have it cached
  6. A generic way to retrieve entity’s id
  7. Clear the cache when we detach

With the reference done, lets move on to listing entities. Wicket provides DataView and DataTable classes that make it easy to list subsets of data – which is exactly what we want when listing entities from a database. The IDataProvider is already very easy to use, but lets see how we can take some noise out of it by creating a simple subclass that specializes it for use with entities:

public abstract class EntityProvider&lt;T&gt; extends SortableDataProvider&lt;T&gt; {
  public EntityProvider() {
    CdiContainer.get().getNonContextualManager().inject(this);
  }
 
  public IModel model(T entity) {
    return new EntityModel(entity);
  }
}

The subclass provides two convenience features:

  1. It automatically injects subclasses
  2. It wraps entities with our EntityModel so we dont have to

    And here is how we would use these two classes to build a table that lists Employees:

    public class HomePage extends WebPage {
     
      public HomePage() {
        add(new DataView("employees", new EmployeeProvider()) {
          @Override protected void populateItem(Item item) {
            IModel user = item.getModel();
            item.add(new Label("first", new PropertyModel(user, "firstName")));
            item.add(new Label("last", new PropertyModel(user, "lastName")));
            item.add(new Label("email", new PropertyModel(user, "email")));
          }
        });
      }
     
      private static class EmployeeProvider extends EntityProvider {
        @Inject EntityManager em;
     
        public Iterator iterator(int first, int count) {
          return em.createQuery("FROM Employee")
            .setFirstResult(first).setMaxResults(count)
            .getResultList().iterator();
        }
     
        public int size() {
          Long count=(Long)em.createQuery("SELECT COUNT(*) FROM Employee")
            .getSingleResult();
          return count.intValue();
        }
      }
    }

    CDI Events

    If we start our application now either using mvn jetty:run command or the provided Start class we will get a page that shows an empty table. Not very exciting. Lets add some code that populates our in-memory database with some data; to do this we need to know when the EntityManagerFactory is created because we need it to insert the data. We are going to do accomplish this by broadcasting a EntityManagerFactoryCreatedEvent event and letting our data initializer listen to it, and when it gets it insert the data.

    Lets create an event object, which is just a POJO:

    public class EntityManagerFactoryCreatedEvent {
      private final EntityManagerFactory emf;
     
      public EntityManagerFactoryCreatedEvent(EntityManagerFactory emf) {
        this.emf = emf;
      }
     
      public EntityManagerFactory getEntityManagerFactory() {
        return emf;
      }
    }

    Now we can fire it from our producer:

    public class EntityMangerFactoryProducer {
     
      @Inject Event<entitymanagerfactorycreatedevent> created; //1
     
      @Produces @ApplicationScoped
      public EntityManagerFactory create() {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("cdidemo");
        created.fire(new EntityManagerFactoryCreatedEvent(emf)); //2
        return emf;
      }
    }
    </entitymanagerfactorycreatedevent>

    1. Inject the Event object used for firing the event, CDI will provide this for us
    2. Fire the event

    And receive it in our data initializer:

    public class ModelInitializer {
      private final String[] firstNames = { "Jacob", "Emily", ... };
      private final String[] lastNames = { "Smith", "Johnson", ... };
     
      private static <T> T random(T[] values) {
        return values[(int)(Math.random() * values.length)];
      }
     
      public void initialize(@Observes EntityManagerFactoryCreatedEvent created) { //1
        EntityManagerFactory emf = created.getEntityManagerFactory(); //2
        EntityManager em = emf.createEntityManager();
     
        em.getTransaction().begin(); //3
        for (int i = 0; i < 30; i++) {
          Employee e = new Employee();
          e.setFirstName(random(firstNames));
          e.setLastName(random(lastNames));
          e.setEmail(e.getFirstName() + "." + e.getLastName() + "@firm.com");
          em.persist(e);
        }
        em.getTransaction().commit();
      }
    }

    1. Declare a listener method for the event, it will be called by the CDI container whenever an event of the correct type is fired
    2. Retrieve the EntityManagerFactory instance from the event
    3. Insert some data into the database

    When we load the home page of our application now, the Employees table will be populated with some data.

    Conclusion

    At this point we have all the basic elements for building a web-application using Wicket, CDI, and JPA. Incidentally, we have also covered and used the three pillars of CDI: dependency injection, contexts, and events. In the next article we will see how to take advantage of the conversation scope to make coding user interfaces with Wicket much simpler.

    The project is available in this github tag

5 Comments

  1. It looks like we need to uncomment the wicket-extensions dependency from the pom generated in the previous blog post in order to pick up SortableDataProvider. Is this correct, or am I missing something?

    • @David: yes

  2. I am totally stuck because I want to use injected EJB Beans for JPA Transaction management as I asked in http://stackoverflow.com/questions/12749502/wicket-with-jpa-and-container-managed-transactions-cmt
    Can You give me a small hint how to do it, as you mentioned a topic for next post? Thank You, Dieter

  3. Should “Indecentally” be changed to “Incidentally” ?

  4. @Diego yes, thank you :)

Submit a Comment