Friday, February 5, 2010

jBPM v3.2.x Hibernate persistence bug - missing javax.jcr.Node

While trying to show hibernate persistence with jBPM v3.2.x I ran into a problem with a missing dependency. Details of the simple POJO class I was persisting, the hibernate mappings, error message encountered and solution tracing are provided below for those interested:

package com.sample.model;

// Sample person object for persistence checking.
public class Person {

 private Integer ssn;
 private String lastname;
 private String firstname;

 public void setFirstname(String firstname) {
  this.firstname = firstname;
 }
 public String getFirstname() {
  return firstname;
 }
 public void setLastname(String lastname) {
  this.lastname = lastname;
 }
 public String getLastname() {
  return lastname;
 }
 public void setSSN(Integer ssn) {
  this.ssn = ssn;
 }
 public Integer getSSN() {
  return ssn;
 }
}

The hibernate mappings were put into the person.hbm.xml file:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.sample.model" auto-import="false" default-access="field">
  <class name="Person">
   <id name="ssn" column="SSN"><generator class="native" /></id>
   <property name="lastname" column="LASTNAME" />
   <property name="firstname" column="FIRSTNAME" />
  </class>
</hibernate-mapping>

// First the errors I was getting in my logging (just the last bits):
...
DEBUG GraphElement - event 'process-start' on ProcessDefinition(main_flow)
 for Token(/)
DEBUG VariableContainer - create variable 'person' in 'TokenVariableMap[/]' 
with value 'com.sample.model.Person@1dfc547'
DEBUG Converters - adding converter 'D', 'org.jbpm.context.exe.converter.DoubleToStringConverter'
DEBUG Converters - adding converter 'C', 'org.jbpm.context.exe.converter.CharacterToStringConverter'
DEBUG Converters - adding converter 'B', 'org.jbpm.context.exe.converter.BooleanToStringConverter'
DEBUG Converters - adding converter 'Y', 'org.jbpm.context.exe.converter.BytesToByteArrayConverter'
DEBUG Converters - adding converter 'A', 'org.jbpm.context.exe.converter.DateToLongConverter'
DEBUG Converters - adding converter 'R', 'org.jbpm.context.exe.converter.SerializableToByteArrayConverter'
DEBUG Converters - adding converter 'I', 'org.jbpm.context.exe.converter.IntegerToLongConverter'
DEBUG Converters - adding converter 'H', 'org.jbpm.context.exe.converter.ShortToLongConverter'
DEBUG Converters - adding converter 'G', 'org.jbpm.context.exe.converter.FloatToDoubleConverter'
DEBUG Converters - adding converter 'F', 'org.jbpm.context.exe.converter.FloatToStringConverter'
DEBUG Converters - adding converter 'E', 'org.jbpm.context.exe.converter.ByteToLongConverter'
DEBUG HibernateLongIdMatcher - no current context so valueClass 
cannot be stored as a long-id-ref to a hibernate object
DEBUG HibernateStringIdMatcher - no current context so valueClass 
cannot be stored as a string-id-ref to a hibernate object

The path to the missing interface we traced from jbpm-jpdl.jar -> org.jbpm.context.exe -> jbpm.varmapping.xml file contains the following mapping:

<!-- JSR 170 JCR Node -->
    <jbpm-type>
      <matcher>
        <bean class="org.jbpm.context.exe.matcher.JcrNodeMatcher" />
      </matcher>
      <variable-instance class="org.jbpm.context.exe.variableinstance.JcrNodeInstance" />
    </jbpm-type>    

This leads to org.jbpm.context.exe.matcher.JcrNodeMatcher.class which imports the class not included in jBPM:

/*
 * Snipped the license code.
 */
package org.jbpm.context.exe.matcher;

import javax.jcr.Node;        <<<<<<<<<<<<<< MISSING!!!!

import org.jbpm.context.exe.JbpmTypeMatcher;

public class JcrNodeMatcher implements JbpmTypeMatcher {

  private static final long serialVersionUID = 1L;

  public boolean matches(Object value) {
    return (Node.class.isAssignableFrom(value.getClass()));
  }

}

My solution: added external jar to projects classpath, jcr-1.0.jar which provides the needed interface interface. Hope this saves you some time!