Hibernate OGM / JAX-RS / JAX-WS redeployment issue on WildFly8.2: java.lang.NoSuchMethodException: org.objectweb.asm.MethodWriter.visitLabel

I’ve been struggling with failing redeploys on WildFly8.2 while I’m developing my app. If the app is deployed, on first server start it starts up fine, but then if I redeploy some code changes I get this NoSuchMethodException in the asm library, suggesting I’ve got some conflict of versions of the asm library used by my app:

Caused by: java.lang.NoSuchMethodException: org.objectweb.asm.MethodWriter.visitLabel(org.objectweb.asm.Label)
 at java.lang.Class.getMethod(Class.java:1773) [rt.jar:1.8.0_20]
 at org.apache.cxf.common.util.ReflectionInvokationHandler.invoke(ReflectionInvokationHandler.java:85)
 ... 28 more

Luckily I came across this post with the same error, putting me on the right direction about the possibility of my app being packaged with a conflicting version of asm. Looking at a ‘mvn dependency:tree’ on my app, I could see asm being pulled in from my use of Hibernate OGM and Jersey as transitive dependencies.

Despite trying to add excludes to not get asm included in the packaging of my app, I eventually gave up and decided to just remove my luckily minimal use of Hibernate OGM. I think the issue was caused my OGM’s deployment of modules onto the WildFly server, one of which was asm. After I had removed OGM from my app, removed the modules, I was back to speedy redeploys of my app.

I’m sure there’s a way to get OGM to deploy happily, or maybe I had just ran across an asm version conflict with other libraries my app is using (Jersey?), but I don’t have time right now to deal with it. Another project for another day 🙂

Using Hibernate OGM to persist objects to MongoDB (deploying to Wildfly 8.2)

For storing data when you’re less concerned about relationships between your data but more interested in entities (documents) and their attributes, a document-based datastore like MongoDB makes a lot of sense. MongoDB’s Java Driver API though is rather clunky in it’s usage pattern.

So I started looking for alternatives. The MongoDB Java ecosystem page has a good collection of some libraries to consider. Initially I took a quick look at MongoJack, which looked like an interesting approach to map between Java POJOs to json data representations (using the Jackson api). I remember reading a while back at Morphia, and was interested what a JPA based approach to interacting with MongoDB would look like. Somewhere I stumbled across the Hibernate OGA project – being a fan of ORM approaches popularized by Hibernate, I wanted to take a look.

The current Hibernate OGM docs (4.1) are here.

For deploying on JBoss/WildFly, OGM is supplied as modules in a zip that you can unzip directly into the modules dir on the server. See here more more details.

Deploying to OpenShift, as for most cartridges, your configuration values are defined in environment variables. Instead of hardcoding the properties and values in your persistence.xml, you can have them passed to your server at startup by adding them to a JAVA_OPTS_EXT file like this (do this one time to create the file):

echo "-Dhibernate.ogm.datastore.host=$OPENSHIFT_MONGODB_DB_HOST \
    -Dhibernate.ogm.datastore.port=$OPENSHIFT_MONGODB_DB_PORT \
    -Dhibernate.ogm.datastore.username=$OPENSHIFT_MONGODB_DB_USERNAME \
    -Dhibernate.ogm.datastore.password=$OPENSHIFT_MONGODB_DB_PASSWORD" \
    > .env/user_vars/JAVA_OPTS_EXT

Mapping your Entities and Id properties

At some point support for the ObjectId MongoDB id type was added. In the current docs don’t use the uuid id generator, use the ‘objectid’ type described here instead:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Type(type = "objectid")

 

JPA Persistence.xml

Here’s what my persistence.xml looks like:
[code language=”xml”]

org.hibernate.ogm.jpa.HibernateOgmPersistence if entities not in same jar, list here

[/code]

Using Spring with JPA and Hibernate

Spring + Hibernate

  • HibernateTemplate is now obsolete (Spring 3.x +) – create bean for SessionFactory and wire it into Hibernate-based Repository beans
  • Use the Hibernate Session api directly
  • This approach has zero dependency on Spring APIs

How to configure:

Configure beans for your datasource, transaction manager and the SessionFactory:

<jee:jndi-lookup id="myDataSource" jndi-name="java:comp/env/jdbc/myds"/>

<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />

<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="myDataSource"/>
    <property name="jtaTransactionManager" ref="txManager"/> 
    <property name="mappingResources">
      <list>
        <value>product.hbm.xml</value>
      </list>
    </property>
    <property name="hibernateProperties">
      <value>
        hibernate.dialect=org.hibernate.dialect.HSQLDialect
      </value>
    </property>
  </bean>

Configuring with xml files is optional if you’re using JPA annotations for your Entities instead.

Repositories using Hibernate follow same ‘new’ pattern as JDBC Template with Spring 3.x, no longer user the HibernateTemplate, inject a Hibernate SessionFactory and use this to get a Session directly. This approach doesn’t have any Spring code dependencies:

@Transactional
@Repository
public class ExampleRespositoryImpl implements ExampleRepository
{
  private SessionFactory sessionFactory;

  public ExampleRespositoryImpl(SessionFactory sessionFactory)
  {
    this.sessionFactory(sessionFactory);
  }

  public Example findExampleById(Long id)
  {
    this.sessionFactory.getCurrentSession().get(Example.class, id);
  }
}

Spring + JPA

How to configure:

Running in an EE container, configure your datasource, transaction manager and EntityManagerFactoryBean:

<jee:jndi-lookup id="dataSource" jndi-name="java:jboss/datasources/MysqlDS"/>

<bean id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>

<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/persistenceUnit"/>

If you’re running outside of an EE container, instead of looking up your datasource and container provided EntityManagerFactory, define a LocalEntityMangerFactoryBean, referencing your persistence unit name:

<bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="persistenceUnit"/>
    <property name="dataSource" ref="dataSource"/>
 </bean>

Configure your persistence.xml to reference your datasource and JPA provider (which may also be Hibernate):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="JTA"><!-- for local testing use: RESOURCE_LOCAL -->
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
         <!-- KH: look up DataSource from container -->
         <jta-data-source>java:jboss/datasources/MysqlDS</jta-data-source>

        <properties>
            <!-- KH: ask JBoss to publish the EntityManager so we can reference it in the Spring config -->
            <property name="jboss.entity.manager.factory.jndi.name" value="persistence/persistenceUnit"/>

            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
            <!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
            <property name="hibernate.hbm2ddl.auto" value="update"/>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
            <property name="hibernate.connection.charSet" value="UTF-8"/>

        </properties>
    </persistence-unit>
</persistence>

If you’re running outside of an EE container, make the following changes:

  • transaction-type="RESOURCE_LOCAL"
  • remove the <jta-data-source> element

Write Repositories with @Repository and @Transactional, and use the @PuersistenceUnit annotation to inject the EntityManagerFactory

@Transactional
@Repository
public class ExampleRespositoryImpl implements ExampleRepository
{
  private EntityManagerFactory emf;

    @PersistenceUnit
    public void setEntityManagerFactory(EntityManagerFactory emf) {
        this.emf = emf;
    }

    public Collection loadProductsByCategory(String category) {
        EntityManager em = this.emf.createEntityManager();
        try {
             Query query = em.createQuery("from Product as p where p.category = ?1");
             query.setParameter(1, category);
             return query.getResultList();
        }
        finally {
            if (em != null) {
                em.close();
            }
        }
    }
}

This approach injects the EntityManagerFactory using @PersistenceUnit, from which you can get hold of the EntityManager. The normal approach with JPA would be to inject the EntityManager with @PersistenceContext and use the EntityManager directly.

Location of JPA persistence.xml to auto find entities

I’m working on some example code to show different configuration options and approaches for using Hibernate with JPA. I just noticed that the location of the /META-INF/persistence.xml file is critical to allow Hibernate to auto-locate your annotated entities.

In order for the auto location to work (to avoid having to explicitly list annotated entities in your persistence.xml or hibernate.cfg.xml files), the persistence.xml file must be bundled in the same jar as the entities. If you move the file elsewhere, then the entities are not found, even if they are in the classpath. To workaround this, if you do need to put the persistence.xml file in a different location, use the <mapping> element to explicitly declare the entities.