Camunda Team Blog

{ "json" : "everywhere" } - How to use json in a process

Written by Roman Smirnov on , under Execution category.
Since Camunda BPM platform 7.2 it is very easy to read, write and manipulate json objects by using Camunda Spin. Among other things, this feature is used to serialize Java objects inside a process instance in the process engine.

But what if you want to use Json Variables without mapping to Java objects? With the next alpha release we will introduce a new ValueType "json" (and "xml" but that is an other story).

In this post I demonstrate how you can use the json value type to

  • implement HTML Forms which work with a Json Variable,
  • implement BPMN Sequence Flow conditions based on the properties of the Json Variable.


Example Process

In this post I use the following example process:



Create a Json variable in a start form

The process instance is started by using a plain Html form inside camunda Tasklist.

<form role="form" class="form-horizontal">
  <script cam-script type="text/form-script">

    var customer = $scope.customer = {};

    camForm.on('form-loaded', function () {
      // declare a 'json' variable 'customer'
      camForm.variableManager.createVariable({
        name: 'customer',
        type: 'json',
        value: customer
      });
    });

  </script>
  <div class="control-group">
    <label class="control-label" for="firstName">First Name</label>
    <div class="controls">
      <input id="firstName" class="form-control"
               type="text" ng-model="customer.firstName" required />
    </div>
  </div>

  <!-- Additional fields omitted -->

</form>

The custom java script creates a new object and binds it to the angular $scope of the form as a variable named customer. Then a new process variable named customer will be created when the form has been loaded successfully. The type of the process variable is set to json, so that the variable will be persisted simply as json without the need to deserialize it to a custom Java object.

The form itself is a plain angular form (see ng-model binding of input field).

Accessing an existing Json variable in a task form

An existing json variable can be accessed using custom java script. The pattern is to fetch first the value of the variable and then bind it to an angular scope variable:

<form role="form" class="form-horizontal">
  <script cam-script type="text/form-script">

    camForm.on('form-loaded', function () {
      // tell the form SDK to fetch the json variable name 'customer'
      camFom.variableManager.fetchVariable('customer');
    });

    camForm.on('variable-fetched', function () {
      // work with the variable (bind it to current angular $scope)
      $scope.customer = camForm.variableManager.variableValue('customer');
    });

  </script>
  <div class="control-group">
    <label class="control-label" for="firstName">First Name</label>
    <div class="controls">
      <input id="firstName" class="form-control"
             type="text" ng-model="customer.firstName" required />
    </div>
  </div>

  <!-- Additional fields omitted -->

</form>

Accessing an existing json variable in an expressions

In the past you could already store Json as variable values. However, you needed to store it as a String variable. The problem with that is that in a sequence flow you cannot easily write EL Expressions using the properties of the json if it is stored as a String.

In Camunda 7.2 we introduced Spin and it became possible to pare the String within El and use the Spin API for formulating conditions:

${ JSON(customer).prop("age").numberValue() >= 21}

While this was a huge improvement the problem is that if you need to interpret the same variable as Json multiple times within a command, it needs to be parsed multiple times (among other downsides).
Now that we introduce Json variables as native ValueTypes, you can directly access the properties of a Json variable in conditions:

<sequenceFlow id="SequenceFlow_4" name="age above 21"
    sourceRef="ExclusiveGateway_1" targetRef="UserTask_2">
  <conditionExpression xsi:type="tFormalExpression">
    <![CDATA[
      ${ customer.prop("age").numberValue() >= 21 }
    ]]>
  </conditionExpression>
</sequenceFlow>

<sequenceFlow id="SequenceFlow_5" name="age under 21"
    sourceRef="ExclusiveGateway_1" targetRef="UserTask_3">
  <conditionExpression xsi:type="tFormalExpression">
    <![CDATA[
      ${ customer.prop("age").numberValue() < 21 }
    ]]>
  </conditionExpression>
</sequenceFlow>


The example resources can be found here.