I am using JBoss jBPM and storing a java 1.5 enum in a JBPM StringInstance (subclass of VariableInstance, see mapping below). To do this, JBPM recommends creating a Converter which basically has a convert() and revert() method. This appears to work fine for creating & retrieving TaskInstances through JBPM, but sometimes we need to access the Hibernate Session directly to execute a more complex query (via Criteria / HQL), see below. What I am trying to do is supply a List of enum values to Hibernate, but Hibernate throws a ClassCastException, because JBPM is storing the enums as StringInstances in Oracle, via the Converter.
So, I guess the first question is, am I at all going about this in the right way? If so, I believe I need some way of letting Hibernate know how JBPM is representing the Enum as a String in Oracle. I've seen the EnumUserType in the docs, but I don't know where to define this custom type in the mapping, given that this is being stored as a VariableInstance through JBPM's Hibernate mapping.
Also, I have tried supplying the String representation from the Converter as the parameters to Hibernate, and this is not working for some reason .. with DEBUG logging, I see the SQL query and I see the parameter bindings ... if I duplicate those in my SQL runner, I get a result back, but Hibernate does not. This is possibly because Hibernate doesn't know how to convert the StringInstance back to an Enum?! I'm not sure ... but DEBUG says that there are 0 rows in the ResultSet, when I clearly get a row returned running the SQL manually.
Hibernate version:
3.1, bundled with JBoss jBPM 3.1.1
Mapping documents:
Code:
<class name="org.jbpm.context.exe.VariableInstance"
table="JBPM_VARIABLEINSTANCE"
abstract="true"
discriminator-value="V">
<id name="id" column="ID_"><generator class="native" /></id>
<discriminator type="char" column="CLASS_"/>
<!-- V : org.jbpm.context.exe.VariableInstance -->
<!-- B : org.jbpm.context.exe.variableinstance.ByteArrayInstance -->
<!-- D : org.jbpm.context.exe.variableinstance.DateInstance -->
<!-- O : org.jbpm.context.exe.variableinstance.DoubleInstance -->
<!-- H : org.jbpm.context.exe.variableinstance.HibernateLongInstance -->
<!-- I : org.jbpm.context.exe.variableinstance.HibernateStringInstance -->
<!-- L : org.jbpm.context.exe.variableinstance.LongInstance -->
<!-- S : org.jbpm.context.exe.variableinstance.StringInstance -->
<!-- N : org.jbpm.context.exe.variableinstance.NullInstance -->
<property name="name" column="NAME_"/>
<property name="converter"
column="CONVERTER_"
type="org.jbpm.db.hibernate.ConverterEnumType" />
<many-to-one name="token"
column="TOKEN_"
foreign-key="FK_VARINST_TK" />
<many-to-one name="tokenVariableMap"
column="TOKENVARIABLEMAP_"
foreign-key="FK_VARINST_TKVARMP" />
<many-to-one name="processInstance"
column="PROCESSINSTANCE_"
foreign-key="FK_VARINST_PRCINST" />
</class>
Code between sessionFactory.openSession() and session.close():Code:
Criteria crit = session.createCriteria(TaskInstance.class)
crit.setFetchMode("variableInstances", FetchMode.JOIN);
crit.setMaxResults(15);
Criteria vars = hbnCriteria2.createCriteria("variableInstances");
vars.add(Restrictions.and(
Restrictions.eq("name", "status"),
Restrictions.in("value", tskSearch.getStatuses())));
return crit.list();
tskSearch.getStatuses() returns a List<TaskStatus> where TaskStatus is an enum {NEW,ACTIVE,...}
Full stack trace of any exception that occurs:
Quote:
java.lang.ClassCastException: com.amfam.workflow.ewsng.dto.TaskStatus
at org.hibernate.type.StringType.toString(StringType.java:44)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:89)
at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:63)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1514)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1576)
at org.hibernate.loader.Loader.doQuery(Loader.java:661)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:224)
at org.hibernate.loader.Loader.doList(Loader.java:2150)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2029)
at org.hibernate.loader.Loader.list(Loader.java:2024)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:94)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1492)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:298)
at com.amfam.workflow.ewsng.helper.HbnQuery.getList(HbnQuery.java:72)
at com.amfam.workflow.ewsng.helper.test.HbnQueryTest.testAddStatuses(HbnQueryTest.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Name and version of the database you are using:Quote:
Server: Oracle9i Enterprise Edition Release 9.2.0.7.0 - 64bit Production
JDBC Driver: Oracle JDBC driver, version: 9.2.0.4.0
The generated SQL (show_sql=true):Quote:
select * from ( select this_.ID_ as ID1_23_1_, this_.NAME_ as NAME3_23_1_, this_.DESCRIPTION_ as DESCRIPT4_23_1_, this_.ACTORID_ as ACTORID5_23_1_, this_.CREATE_ as CREATE6_23_1_, this_.START_ as START7_23_1_, this_.END_ as END8_23_1_, this_.DUEDATE_ as DUEDATE9_23_1_, this_.PRIORITY_ as PRIORITY10_23_1_, this_.ISCANCELLED_ as ISCANCE11_23_1_, this_.ISSUSPENDED_ as ISSUSPE12_23_1_, this_.ISOPEN_ as ISOPEN13_23_1_, this_.ISSIGNALLING_ as ISSIGNA14_23_1_, this_.ISBLOCKING_ as ISBLOCKING15_23_1_, this_.TASK_ as TASK16_23_1_, this_.TOKEN_ as TOKEN17_23_1_, this_.SWIMLANINSTANCE_ as SWIMLAN18_23_1_, this_.TASKMGMTINSTANCE_ as TASKMGM19_23_1_, variablein1_.ID_ as ID1_21_0_, variablein1_.NAME_ as NAME3_21_0_, variablein1_.CONVERTER_ as CONVERTER4_21_0_, variablein1_.TOKEN_ as TOKEN5_21_0_, variablein1_.TOKENVARIABLEMAP_ as TOKENVAR6_21_0_, variablein1_.PROCESSINSTANCE_ as PROCESSI7_21_0_, variablein1_.BYTEARRAYVALUE_ as BYTEARRA8_21_0_, variablein1_.DATEVALUE_ as DATEVALUE9_21_0_, variablein1_.DOUBLEVALUE_ as DOUBLEV10_21_0_, variablein1_.LONGIDCLASS_ as LONGIDC11_21_0_, variablein1_.LONGVALUE_ as LONGVALUE12_21_0_, variablein1_.STRINGIDCLASS_ as STRINGI13_21_0_, variablein1_.STRINGVALUE_ as STRINGV14_21_0_, variablein1_.CLASS_ as CLASS2_21_0_ from JBPM_TASKINSTANCE this_ inner join JBPM_VARIABLEINSTANCE variablein1_ on this_.ID_=variablein1_.TASKINSTANCE_ where (variablein1_.NAME_=? and variablein1_.STRINGVALUE_ in (?, ?)) ) where rownum <= ?
Debug level Hibernate log excerpt:Quote:
11:50:28,663 [main] DEBUG Printer : listing entities:
11:50:28,673 [main] DEBUG Printer : org.jbpm.context.exe.variableinstance.StringInstance{processInstance=null, value=class com.amfam.workflow.ewsng.dto.TaskStatus,NEW, tokenVariableMap=null, converter=null, token=null, name=status, id=3352104}
11:50:28,673 [main] DEBUG Printer : org.jbpm.taskmgmt.exe.TaskInstance{comments=<uninitialized>, isBlocking=false, start=null, variableInstances=[org.jbpm.context.exe.VariableInstance#3352104], taskMgmtInstance=null, isSuspended=false, isOpen=true, end=null, swimlaneInstance=null, dueDate=null, token=null, pooledActors=<uninitialized>, id=3352103, actorId=actor1, isSignalling=true, create=null, description=null, isCancelled=false, task=null, name=null, priority=3}
11:50:28,673 [main] DEBUG DefaultAutoFlushEventListener : Dont need to execute flush
11:50:28,673 [main] DEBUG AbstractBatcher : about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
11:50:28,673 [main] DEBUG AbstractBatcher : select * from ( select this_.ID_ as ID1_23_1_, this_.NAME_ as NAME3_23_1_, this_.DESCRIPTION_ as DESCRIPT4_23_1_, this_.ACTORID_ as ACTORID5_23_1_, this_.CREATE_ as CREATE6_23_1_, this_.START_ as START7_23_1_, this_.END_ as END8_23_1_, this_.DUEDATE_ as DUEDATE9_23_1_, this_.PRIORITY_ as PRIORITY10_23_1_, this_.ISCANCELLED_ as ISCANCE11_23_1_, this_.ISSUSPENDED_ as ISSUSPE12_23_1_, this_.ISOPEN_ as ISOPEN13_23_1_, this_.ISSIGNALLING_ as ISSIGNA14_23_1_, this_.ISBLOCKING_ as ISBLOCKING15_23_1_, this_.TASK_ as TASK16_23_1_, this_.TOKEN_ as TOKEN17_23_1_, this_.SWIMLANINSTANCE_ as SWIMLAN18_23_1_, this_.TASKMGMTINSTANCE_ as TASKMGM19_23_1_, variablein1_.ID_ as ID1_21_0_, variablein1_.NAME_ as NAME3_21_0_, variablein1_.CONVERTER_ as CONVERTER4_21_0_, variablein1_.TOKEN_ as TOKEN5_21_0_, variablein1_.TOKENVARIABLEMAP_ as TOKENVAR6_21_0_, variablein1_.PROCESSINSTANCE_ as PROCESSI7_21_0_, variablein1_.BYTEARRAYVALUE_ as BYTEARRA8_21_0_, variablein1_.DATEVALUE_ as DATEVALUE9_21_0_, variablein1_.DOUBLEVALUE_ as DOUBLEV10_21_0_, variablein1_.LONGIDCLASS_ as LONGIDC11_21_0_, variablein1_.LONGVALUE_ as LONGVALUE12_21_0_, variablein1_.STRINGIDCLASS_ as STRINGI13_21_0_, variablein1_.STRINGVALUE_ as STRINGV14_21_0_, variablein1_.CLASS_ as CLASS2_21_0_ from JBPM_TASKINSTANCE this_ inner join JBPM_VARIABLEINSTANCE variablein1_ on this_.ID_=variablein1_.TASKINSTANCE_ where (variablein1_.NAME_=? and variablein1_.STRINGVALUE_ in (?, ?)) ) where rownum <= ?
11:50:28,673 [main] DEBUG AbstractBatcher : preparing statement
11:50:28,683 [main] DEBUG NullableType : binding 'status' to parameter: 1