Java object serialization fails to decode after user task


#1

Hi all,

As a heads up: I am new to both Camunda and Java :slight_smile:

My issue: I can serialize/deserialize a Java object in a delegate using execution.setVariable('varName', javaInstanceVariable);. The workflow has only service tasks (all delegate code) and a gateway and successfully serializes/deserializes the object in each step. However, if I add a User Task in between any of the service tasks, then the object is no longer deserialized correctly…all of the properties are null and the parameterless constructor is called. With only service tasks, the parameterless constructor is not called.

My setup: I’m using the prebuilt distribution of Camunda 7.7 with Tomcat 8.0.24 and can see the Java object’s values by simply logging them in each service task.

Details:
My class:

public class Project {
  private final Logger LOGGER = Logger.getLogger(Project.class.getName());
  public static enum Types {
     TYPE_1, TYPE_2, TYPE_3
    
    private String _value;
    private Types(final String val) {
      _value = val;
    }
    
    public String toString() {
      return _value;
    }
  }

  private String id;
  private Types type;
  private String assignee;
  public Project() {}
  public Project(final String projectId, final Types projectType) {
    id = projectId;
    type = projectType;
  }
  
 // setters and getters
}

In the first service task, I instantiate this class using data from the submitted form, and set it to a variable:

Project instance = new Project(execution.getVariable('id').toString(), Types.valueOf(execution.getVariable('type').toString());
execution.setVariable('instance', instance);

…and retrieve the value by using:
Project instance = (Project) execution.getVariable('instance');

So, that will correctly set the properties id and type that were provided by the form in all service tasks before the User Task and the parameterless constructor is not called. After the the User Task completes, the instance properties are null…and the parameterless constructor called.

I’m sure there’s something I’m not understanding about either execution context, variable hierarchy, or Java serialization. If there’s any more information that could be of use, please let me know.

Any help is much appreciated! Thanks!


#2

I still haven’t figured out this issue, but I do have a work-around. For now, I’m serializing the instance variable to JSON and storing it in a separate variable. Once the User Task is complete, I create an instance of the class and use the data in the JSON object to populate the instance. That instance can then be serialized as a Java object until the next User Task.


#3

Hi @stone-joe,

As soon as you have a user task (or any other wait state), the process engine must persist the process state to the database. This requires serialization of variables. Without such a wait state, the engine always uses the initally provided object, which of course does not change.

In Camunda, there are different ways of serialization for custom object variables, see https://docs.camunda.org/manual/7.7/user-guide/process-engine/variables/#object-value-serialization. If your class implements java.io.Serializable, the engine will use Java’s default serialization mechanism. This is not the case here, so the engine chooses either XML or JSON to serialize the object. For those to work, your class must have appropriate getter and setter methods for the properties id, type, etc. or else, the serialization result will be equivalent to an empty object.

Cheers,
Thorben


#4

So a lack of understanding when/why Camunda serializes variables on my part :slight_smile:

Thanks for the insight!