Weird result when storing process variables of different types in a Map<String, Object> with variables of type JSON


#1

Hello fellow camunda-users,

i am building an application were i store the data created by the interface as a variable of type json:

data = {
  activation: null,
  users: ["user1"],
  roles: ["role1", "role2"],
  userRoleConnections: [{user: "user1", role: "role1"}, {user: "user1", role: "role2"}]],
  group : 'approver'
}
processedData = {
  variables: { 
    data: {value: JSON.stringify(data), type: 'Json'}
  }
};
const request = jQuery.ajax({
  method: 'POST',
  contentType: 'application/json',
  url: '/myUrl/',
  data: JSON.stringify(processedData),
  dataType: 'json'
});

It stores the values just fine. When i look it up in cockpit it shows exactly what i expect to see.
But when i try to load the data back into my application by calling my custom REST endpoint, it will give me some realy weird output:

{
    "taskDto": {
        "id": "991f9926-13f9-11e9-b9d6-0242ac120006",
        "a-lot-of-expected-properties": "expectedValues"
    },
    "taskVariableMap": {
        "data": {
            "nodeType": "OBJECT",
            "string": false,
            "object": true,
            "number": false,
            "boolean": false,
            "value": false,
            "dataFormatName": "application/json",
            "array": false,
            "null": false
        },
        "someOtherVariableTypeString": "expectedValue",
        "timeStamp": expectedValue,
        "someVariableTypeBool": true // as expected
    }
}

As you can see, the data Variable inside of the taskVariableMap is not what i sent and not what i see in cockpit when i lookup the process variables.

Here is some of the code used to get the data:
Data class:

public class TaskDTO {
    private TaskDto taskDto; // camunda TaskDto class
    private Map<String, Object> taskVariableMap;
    // getter and setters
}

customRestService code:

Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
TaskDTO taskDTO = new TaskDTO();
taskDTO.setTaskDto(TaskDto.fromEntity(task));
Map<String, Object> vm = runtimeService.getVariables(taskDto.getExecutionId());
taskDTO.setTaskVariableMap(vm);

The other code parts should not affect this behaviour. When i sent the data variable as a String and not as a Json, the code worked perfectly fine. But the drawback was, that it was possible to choose a lot of users/roles. Type String camunda variables were to small to fit my needs.

Thanks in advance,
Pascal

Edit:
I fixed the issue, but i think it’s pretty nasty. So if you got an advice or a better solution, i am open minded to almost everything :smiley:
What i do now is the following. First, i get all variables. Since i got some processes that are missing the “data” variable, i will then check if it is present. If it is, i will get the Typed-Version of the variable and store it as a string in a new variable. Then i will remove the “data” variable from the map. Afterwards i check if the String variable is something else than empty String and save put it with key “data” to the variable again.

Map<String, Object> vm = runtimeService.getVariables(taskDto.getExecutionId());
String dataValueAsString = "";
if (vm.containsKey("data")) {
    JsonValue dataValue = runtimeService.getVariableTyped(taskDto.getExecutionId(), "data");
    dataValueAsString = dataValue.getValue().toString();
    vm.remove("data");
}
if (dataValueAsString != "") {
    vm.put("data", dataValueAsString);
}

In my webapp backend, i will then parse the result back to JSON again. As i said, it is nasty… but it works :stuck_out_tongue: