External Task Client JsonNode return for multi-instance processing

Morning,

I am using Camunda to process a set of marketing operations on our system.

The BPMN model:

External Task 1: “Generate Operation dependencies”
This external task queries data on marketing operations and provides this as a JSON array.
The output has to be provided in a map, so the SpinJsonNode is added as the object

Code:

import static org.camunda.spin.Spin.*;
import org.camunda.bpm.client.ExternalTaskClient;
import org.camunda.spin.json.SpinJsonNode;

…some other code

        SpinJsonNode operations_json = JSON("[]");    //setup JSON array

        for (int i = 0; i < number_of_operations; i++) {  //loop through operations appending to JSON array

            SpinJsonNode operation = JSON("{}")   
                    .prop("operation_id", operationid)
                    .prop("customer_id", customerid)
                    .prop("task_id", taskid)
            operations_json.append(operation);
        }

        Map<String, Object> operations = new HashMap<>();   // external task return must be map
        operations.put("operations" , operations_json);  //SpinJsonNode is put into map

        externalTaskService.complete(externalTask, operations);  //external task is completed

The map (operations) sent back to Camunda looks like this.

operations:[
{
“operation_id”:1568,
“customer_id”:492,
“task_id”:4
},
{
“operation_id”:1569,
“customer_id”:419,
“task_id”:11
},
{
“operation_id”:1570,
“customer_id”:491,
“task_id”:19
}
]

External Task 2: “Process Operations”
This task will receive the ‘operations’ output of the first external task and iterate through the provided JSON array, providing each to multi-instance external tasks.

In my multi-instance configuration I have the following:

Collection: ${operations.elements()}
Element Variable: operation

Each multi-instance should get a element of the operations array and should therefore have the variable ‘operation’ with just

{
    "operation_id":1570,
    "customer_id":491,
    "task_id":19
}

This is where things start to fall apart… on the Camunda process engine I get the following errors.

http-nio-8080-exec-3] ERROR org.camunda.bpm.engine.context - ENGINE-16004 Exception while closing command context: Error while evaluating expression: ${operations.elements()}. Cause: Cannot deserialize object in variable ‘operations’: SPIN/JACKSON-JSON-01006 Cannot deserialize ‘{“array”:t…’ to java type ‘[simple type, class org.camunda.spin.impl.json.jackson.JacksonJsonNode]’
org.camunda.bpm.engine.ProcessEngineException: Error while evaluating expression: ${operations.elements()}. Cause: Cannot deserialize object in variable ‘operations’: SPIN/JACKSON-JSON-01006 Cannot deserialize ‘{“array”:t…’ to java type '[simple type, class org.camunda.spin.impl.json.jackson.JacksonJsonNode]’
at org.camunda.bpm.engine.impl.el.JuelExpression.getValue(JuelExpression.java:69)
at org.camunda.bpm.engine.impl.el.JuelExpression.getValue(JuelExpression.java:51)
at org.camunda.bpm.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior.resolveNrOfInstances(MultiInstanceActivityBehavior.java:107)

Caused by: org.camunda.bpm.engine.ProcessEngineException: Cannot deserialize object in variable ‘operations’: SPIN/JACKSON-JSON-01006 Cannot deserialize ‘{“array”:t…’ to java type ‘[simple type, class org.camunda.spin.impl.json.jackson.JacksonJsonNode]’
at org.camunda.bpm.engine.impl.variable.serializer.AbstractSerializableValueSerializer.readValue(AbstractSerializableValueSerializer.java:85)
at org.camunda.bpm.engine.impl.variable.serializer.AbstractSerializableValueSerializer.readValue(AbstractSerializableValueSerializer.java:31)

Caused by: org.camunda.spin.json.SpinJsonException: SPIN/JACKSON-JSON-01006 Cannot deserialize ‘{“array”:t…’ to java type '[simple type, class org.camunda.spin.impl.json.jackson.JacksonJsonNode]’
at org.camunda.spin.impl.json.jackson.JacksonJsonLogger.unableToDeserialize(JacksonJsonLogger.java:70)

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of org.camunda.spin.impl.json.jackson.JacksonJsonNode (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
** at [Source: UNKNOWN; line: -1, column: -1]**
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1592)

I have the following in my POM:

    <dependency>
        <groupId>org.camunda.spin</groupId>
        <artifactId>camunda-spin-dataformat-json-jackson</artifactId>
        <version>1.10.1</version>
    </dependency>

Any help you can provide would be super helpful!

1 Like

I faced the same problem. The error seems to suggest that the SpinJsonNode we passed as variable could not be casted into JacksonJsonNode (an extension of SpinJsonNode).

As a workaround, I had to pass a JSON string as a variable, then convert it to SpinJsonNode as I received it.

In the external task handler:

Map<String, Object> variables = new HashMap<>();
variables.put("operations", JSON(operations_json).toString()); // Pass variable as JSON string
externalTaskService.complete(externalTask, variables);

When defining the multi instance class:

  • Collection: ${JSON(operations).elements()} // Convert JSON string into SpinJsonNode and access its elements.
  • Element Variable: operation

I don’t like this workaround though. Hope to see better solutions from the community.

I’m seeing this same issue related to trying to extract JSONPath queries into separate variables. For example, if I receive a large payload from an API call, and want to extract some portion of it and save it into an Array, this same error comes up.

Using this JSON:

[
    {"key": 1},
    {"key": 2},
    {"key": 3}
]

I would like to extract all the values using JSONPath and store them in a variable, but this is proving to be very difficult, and it’s something that I would expect “just works”.

Expression

${JSON(input).jsonPath("$.[*].key").elementList()}

Result Variable

values

I would expect this variable to be serializable, but it throws the same exception as OP. Any help would be very much appreciated.