How can you slowly migrate existing Hibernate apps to JPA? How can you use Hibernate features and unique mapping capabilities with a JPA deployment? How can you take advantage of EJB3 injection and persistence context management with Hibernate? In this blog I want to show how Hibernate, JPA, and EJB 3.0 can co-exist and compliment one another. This information is fully documented between the Hibernate and JBoss EJB3 projects, but I thought I’d highlight them in this blog to make the community aware that they exist.

Mixing and matching JPA annotations within Hibernate

Using the standard JPA annotations helps out greatly in cutting down the amount of XML metadata you have to type. This annotation metadata is an exact replacement for much of the metadata in hbm.xml. Using them does not require you to use the JPA EntityManager interface. You may still use SessionFactory and Session objects to interact with your database. After downing the Hibernate Anotations project, setting things up is fairly easy:

SessionFactory sessionFactory =
                  new AnnotationConfiguration().buildSessionFactory();

You use hibernate.cfg.xml to specify which exact classes you want mapped by this SessionFactory:

<hibernate-configuration>
 <session-factory>
    <mapping class="com.acme.Flight"/>
    <mapping class="org.jboss.Sky"/>
    <mapping resource="org.acme.orm.xml"/>
 </session-factory>
</hibernate-configuration>

You can mix hbm.xml mapping files with new annotated classes. XML resources can also either be JPA-based XML or Hibernate based. This mixing and matching allows you to quickly prototype new mappings using JPA, but allows these mappings to co-exist with older Hibernate 3 applications.

There are a few more options for configuration. Check out the Hibernate Annotations documentation for more information.

Use Hibernate to configure JPA

If you want to use the JPA Entity Manager API to code a portable application, you may still want to use Hibernate metadata to map your beans. Although the JPA orm mapping is pretty rich, it is still a subset of Hibernate’s functionality. The Hibernate Annotations project provides additional Hibernate-specific annotations to elaborate a persistence mapping where JPA leaves off. If you prefer XML, you can use hbm.xml files to define the mappings for your entity beans. When loading a persistence archive, Hibernate Entity Manager will automatically scan the .jar file for any *hbm.xml files and add them to its mapping information.

Hibernate specific configuration is defined in the properties element of the persistence.xml file. You can configure any hibernate property within this XML blob

<persistence>
 <persistence-unit name="manager1" transaction-type="JTA">
    <jta-data-source>java:/DefaultDS</jta-data-source>
    <properties>
       <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
 </persistence-unit>
</persistence>

You may also define all your hibernate configuration in the usual Hibernate way: within a hibernate.xfg.xml file. You must tell the JPA implementation to use this configuration file through the hibernate.ejb.cfgfile property.

<persistence>
 <persistence-unit name="manager1" transaction-type="JTA">
    <jta-data-source>java:/DefaultDS</jta-data-source>
    <properties>
       <property name="hibernate.ejb.cfgfile" value="/hibernate.cfg.xml"/>
    </properties>
 </persistence-unit>
</persistence>

EJB 3.0 managed persistence sessions

EJB 3.0 has some nice integration with JPA. You can have your EJB session beans manage persistent sessions for you, freeing you from having to create, destroy, and clean up your persistence sessions. It can manage your persistent sessions in two ways:

Transaction-scoped persistence contexts

Transaction-scoped persistence contexts can be injected into your stateful, stateless, or message driven beans. These transaction-scoped contexts only live for the duration of the JTA transaction they are invoked within. When you first interact with an injected transaction-scoped EntityManager within a transaction, an underlying persistence context (in other words, a Hibernate session) is transparently created and associated with the transaction. This associated context is propagated automatically to an nested EJBs that invoke on entity managers of the same persistent unit type. This means that any EJB that invokes on an entity manager will be using the same underlying Hibernate Session.

@Statelesspublic class MyBean implements MyInterface {

 @PersistenceContext(unitName="custDb") EntityManager manager;

...

Extended persistence contexts

In Hibernate terminology, an extended persistence context is one particular Hibernate session. This session may live beyond the duration of a JTA transaction. In EJB 3.0, you can inject an extended persistence context into a stateful session bean. Unlike transaction-scoped entity managers, these persistence contexts are not created and destroyed in a transaction, but instead have their lifecylce tied to that of the SFSB session. This allows you to have conversations with your database that span multiple JTA transactions.

@Statefulpublic class ShoppingCartBean implements ShoppingCart {
{
 @PersistenceContext(unitName="custDb", type=EXTENDED) EntityManager manager;
...
}

Using EJB 3.0 injection annotations with Hibernate

The JBoss EJB 3.0 implementation allows you to use Hibernate Session and SessionFactory as types for targets of the @PersistenceContext and @PersistenceUnit annotations. The injected Session or SessionFactory will behave exactly as if you were instead using the JPA counterparts EntityManager or EntityManagerFactory:

@Statelesspublic class MyBean implements MyInterface
{
 @PersistenceContext(unitName="custDb") org.hibernate.Session session;
 @PersistenceUnit(unitName="custDb") SessionFactory factory;
...
}

Just like with the EJB 3.0/JPA integration, the Hibernate Session will be associated with the JTA transaction and propagated to nested EJB invocations within the same transaction. It is also ok if these nested calls use the EntityManager API instead. The same underlying Hibernate session will still be used for both.

Hiberate Sessions can also represent extended persistence contexts:

@Statefulpublic class ShoppingCartBean implements ShoppingCart
{
 @PersistenceContext(type=EXTENDED) org.hibernate.Session session;
...
}

Again, the EJB container will manage this Hibernate Session the same way it would manage an EntityManager instance.

Obtaining Hibernate objects programmatically

You can always get access to a Hibernate Session object from an EntityManager instance through the standard EntityManager.getDelegate() method. This is a JPA specification feature.

  @PersistenceContext EntityManager manager;
  ...
{      org.hibernate.Session session = (Session)manager.getDelegate();  }

The specification, however, does not provide a way to get at the underlying implementation of a Query. Hibernate should provide most of its extended functionality through JPA query hints. For example, lets say you wanted to enable a query cache:

  javax.persistence.Query query = manager.createQuery(...);
  query.setHint("org.hibernate.cacheable", true);

Conclusion

Hibernate and the JBoss EJB 3.0 project provide multiple ways in which you can mix and match Hibernate and JPA annotations and XML metadata. JBoss EJB 3.0 can manage Hibernate typed objects the same way it can manage JPA objects. Finally the specification provides programmatic ways to get at the underlying Hibernate connection. With the features you should have the flexibility to get at the HIbernate features you need while staying as portable as possible under the JPA specification. Or conversely, you can use well-defined JPA mapping annotations within your Hibernate deployments to make coding simpler and easier.

Disclaimer πŸ˜‰ This blog was meant to make you aware of certain integration features that exist between JPA, Hibernate, and JBoss EJB 3.0. You should not use it as a reference guide, but rather dive down deeper into each project’s docoumentation. Have fun.