2 Replies Latest reply on Mar 30, 2011 4:20 AM by k0k0pelli

    Storing a long String (>255 Characters) in a Process Variable is not Possible(?)

    k0k0pelli

      I’m currently working on a process containing a mail task with JBPM 4.4. I need to generate a localized  mail using a preferred language (either German or English). My first approach was to use a separate mail template for each language and then to set the corresponding template by using an expression within the process definition. However, this approach did not succeed, as the process definition could not be deployed because no expressions are allowed in the reference to the mail template. Thus, I had to discard this solution.

       

      Instead I’m currently using a set of variables that are finally used to compose the mail in the template using expression. Nevertheless, some of the text parts are longer than 255 characters, so I cannot use simple strings to be stored as process variables because it results in a data truncation exception thrown by the jdbc driver.

       

      I found out that it should be possible to store a string that is longer than 255 characters by converting it to a char array. jBPM should handle these char[] variables as long text fields in the data base (hibernate type “text”).

       

      However, this seems also not to work, because the internal representation (class org.jbpm.pvm.internal.type.variable.TextVariable) of the char array uses a char[] which is directly passed to hibernate as is. On the other hand, the internal hibernate representation of a long text field (org.hibernate.type.TextType) expects a String object for a text field. This leads to the following exception when trying to store the char[] variable:

       

      Caused by: java.lang.ClassCastException: [C cannot be cast to java.lang.String

          at org.hibernate.type.TextType.toString(TextType.java:94)

          at org.hibernate.type.NullableType.nullSafeToString(NullableType.java:117)

          at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:158)

          at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:131)

          at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2015)

          at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2261)

          at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2678)

          at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)

          at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)

          at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)

          at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)

          at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)

          at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)

          at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)

          at org.jbpm.pvm.internal.tx.HibernateSessionResource.prepare(HibernateSessionResource.java:56)

          at org.jbpm.pvm.internal.tx.StandardTransaction.commit(StandardTransaction.java:107)

          at org.jbpm.pvm.internal.tx.StandardTransaction.complete(StandardTransaction.java:64)

          at org.jbpm.pvm.internal.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:57)

          at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.executeInNewEnvironment(EnvironmentInterceptor.java:53)

          at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)

          at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:56)

          at org.jbpm.pvm.internal.svc.SkipInterceptor.execute(SkipInterceptor.java:43)

          at org.jbpm.pvm.internal.svc.ExecutionServiceImpl.createVariables(ExecutionServiceImpl.java:174)

       

      I think the only way to get it work for character arrays is to implement a converter (org.jbpm.pvm.internal.type.Converter), which is registered in the xml file jbpm.variable.types.xml, and to adapt the isStorable(Object ) method in the type org.jbpm.pvm.internal.type.variable.TextVariable.

       

      Are there any other (simpler) suggestions to work around this problem?

        • 1. Re: Storing a long String (>255 Characters) in a Process Variable is not Possible(?)
          k0k0pelli

          To illustrate the problem, I attached a simple dummy test. After deploying  it (execute the deploy class) and istantiating (using the class CreateInstance) a process with a test variable (testvar) that should be stored in a long text field  is created. the acutal code looks as follows:

           

          ProcessEngine processEngine = new Configuration().setResource("jbpm.cfg.xml").buildProcessEngine();
          
           RepositoryService repositoryService = processEngine.getRepositoryService();
           ExecutionService executionService = processEngine.getExecutionService();
          
           Map<String, Object> variables = new HashMap<String, Object>();
           variables.put("testvar", "This is a test variable for a text".toCharArray());        
           executionService.startProcessInstanceByKey("test", variables);    
          

           

          After  creating the instance with the long text variable testvar, the following exception occurs:

           

          Caused by: java.lang.ClassCastException: [C cannot be cast to java.lang.String

              at org.hibernate.type.TextType.toString(TextType.java:94)

              at org.hibernate.type.NullableType.nullSafeToString(NullableType.java:117)

              at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:158)

              at org.hibernate.type.NullableType.nullSafeSet(NullableType.java:131)

              at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2015)

              at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2261)

              at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2678)

              at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:79)

              at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)

              at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)

              at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)

              at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)

              at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)

              at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)

              at org.jbpm.pvm.internal.tx.HibernateSessionResource.prepare(HibernateSessionResource.java:56)

              at org.jbpm.pvm.internal.tx.StandardTransaction.commit(StandardTransaction.java:107)

              at org.jbpm.pvm.internal.tx.StandardTransaction.complete(StandardTransaction.java:64)

              at org.jbpm.pvm.internal.tx.StandardTransactionInterceptor.execute(StandardTransactionInterceptor.java:57)

              at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.executeInNewEnvironment(EnvironmentInterceptor.java:53)

              at org.jbpm.pvm.internal.svc.EnvironmentInterceptor.execute(EnvironmentInterceptor.java:40)

              at org.jbpm.pvm.internal.svc.RetryInterceptor.execute(RetryInterceptor.java:56)

              at org.jbpm.pvm.internal.svc.SkipInterceptor.execute(SkipInterceptor.java:43)

              at org.jbpm.pvm.internal.svc.ExecutionServiceImpl.createVariables(ExecutionServiceImpl.java:174)

           

          I didn't find an open issue in the ticket tracker. Are there any ideas?

          • 2. Re: Storing a long String (>255 Characters) in a Process Variable is not Possible(?)
            k0k0pelli

            I delved into the jBPM 4.4 code, and I think that there is actually a problem in the classes ch.jbpm.pvm.internal.type.Variable and ch.jbpm.pvm.internal.type.variable.TextVariable. The methods Variable.getObject() and Variable.setObject(…) use the generic type S to get/store the variable. The generic type of the class ch.jbpm.pvm.internal.type.TextVariable is char[]. The value of the type S is passed directly to the corresponding hibernate mapping class org.hibernate.type.TextType which unfortunately expects a String not a char[] as value. Consequently, the excepetion above is thrown.

             

            By relaxing the type to Object in the corresponding methods, as well as by performing several smaller adaptations in the class ch.jbpm.pvm.internal.type.Variable (see attachment), it is possible to circumvent the problem. Nevertheless, the solution is not optimal because it is not clear whether it causes further problems with variables.

             

            Is this problem already known? Are there any other solutions?