Show contents of an ArrayList in an embedded form?


#1

Hi there,

as stated in this example it should be possible to access a process variable and iterate over a java List using ng-repeat.
Now I have adopted the example to a slightly different version but it fails to work completely. The repeated element remains empty.

I have the process variable “billingResults” which contains an ArrayList of class BillingResult.
When I print it directly via {{billingResults}} I get the serialized String of the ArrayList (the same that I see in the Cockpit view).
The difference to the given example is, that in the example the list is nested inside another object, that is deserialized first.

Why does AngularJs know in the example, how to deserialize the list?
Is my problem AngularJs or the Deserialization?
Any help is appreciated.

<form role="form"
      name="variablesForm">

    <script cam-script type="text/form-script">

    camForm.on('form-loaded', function() {
      // fetch the variable named 'billingResults'
      camForm.variableManager.fetchVariable('billingResults');
    });

    camForm.on('variables-fetched', function() {
      // after the variables are fetched, bind the value of billingResults to a angular
      // scope value such that the form can work on it
      $scope.billingResults = camForm.variableManager.variable('billingResults').value;
    });
    </script>

    <h3>Protokoll</h3>
    <p>{{billingResults}}</p>
    <table>
        <tr>
            <th>Typ</th>
            <th>Nachricht</th>
            <th>CDR</th>
        </tr>
        <tr ng-repeat="result in billingResults">
            <td>{{result.resultType}}</td>
            <td>{{result.message}}</td>
            <td>{{result.sourceRecordId}}</td>
        </tr>
    </table>

    <select required
            class="form-control"
            name="Aktion"
            cam-variable-name="FormField_Action"
            cam-variable-type="String">
        <option value="Value_Process">prozessieren</option>
        <option value="Value_Discard" checked>verwerfen</option>
    </select>
</form>


#2

Hi @Brutus5000,

angular does not know how to deserialize an ArrayList. If you inspect what network requests are sent when you inspect a variable in Cockpit, you will find that at first the list of variables is loaded, with their serialized values. We are using this REST endpoint for that. Then, when you click on the variable to inspect it and the modal opens, another request is sent to retrieve the deserialized value (using this REST endpoint). So the deserialization is done on the server.

It looks like you can not even display the deserialized value of your variable in Cockpit. Is that correct? If so, something is wrong with your engine setup that needs to be fixed before we can look at embedded forms.

Best regards
Sebastian


#3

Hi @sebastian.stamm,

yes you are right, even a single BillingResult can not be deserialized. (I am using the default process engine on the preconfigured tomcat distribution for 7.7.0)
It is heavily annotated because I am actually deserializing it from XML which works perfectly.

This is the fairly simple code: (setters are generated at compile time by lombok)
Do my xml annotations interfere with the camunda builtin deserialization? Or is it the enum?

@Setter
public class BillingResult implements Serializable {
    private Type resultType;
    private String message;
    private Integer salesInvoiceDocEntry;
    private String sourceRecordId;
    private Integer originalSalesInvoiceDocEntry;

    @XmlElement(name = "SalesInvoiceDocEntry")
    public Integer getSalesInvoiceDocEntry() {
        return salesInvoiceDocEntry;
    }

    @XmlElement(name = "ResultType")
    public Type getResultType() {
        return resultType;
    }

    @XmlElement(name = "Message")
    public String getMessage() {
        return message;
    }

    @XmlElement(name = "SourceRecordId")
    public String getSourceRecordId() {
        return sourceRecordId;
    }

    @XmlElement(name = "OriginalSalesInvoiceDocEntry")
    public Integer getOriginalSalesInvoiceDocEntry() {
        return originalSalesInvoiceDocEntry;
    }

    @XmlEnum
    public enum Type {
        @XmlEnumValue("success")
        SUCCESS,
        @XmlEnumValue("warn")
        WARNING,
        @XmlEnumValue("error")
        ERROR
    }
}

#4

Looks like I have a general issue with deserialization. I have create a simple TestEntity with a string and an int.

public class TestEntity {
    private String aString;
    private Integer anInteger;
    
    public String getaString() {
        return aString;
    }
    public void setaString(String aString) {
        this.aString = aString;
    }
    public Integer getAnInteger() {
        return anInteger;
    }
    public void setAnInteger(Integer anInteger) {
        this.anInteger = anInteger;
    }
}

This can’t be deserialized either.



#5

All you need is the serialized value as long as you serialize your objects as JSON or XML, i.e. a format that your client can process. The Deserialized tab in Cockpit exists for historical reasons and works in a limited set of setups for objects that are Java-serialized. Whenever you use a shared engine and process applications, Cockpit is not be able to load classes from your application. That is intended and ok.

Edit: What Deserialized actually does is: Cockpit loads the variable from the engine database, accesses its value as a Java object (i.e. attempts to deserialize the persisted value), then serializes it again to JSON and returns it to the client. The second step fails in our case here.


#6

Ok I was able to solve my problem.
A single instance of the class was serialized properly as JSON without any additional steps.
.
However, as soon as wrapped in a list I got a serialization-error. Now my error: To solve this I implemented the Serializable-interface, but that led to the representation in JVM byte code. Another thing I noticed it, that the ArrayList had no concrete type in the camunda cockpit.

Now I wrap the list in an ObjectValue and now the type is stored properly and the serialization works. The type of the list is also visible in cockpit at the process variables.

Maybe @thorben can confirm that this is the correct approach in general? :slight_smile:


#7

Sounds good. Well done :slight_smile:


#8

Hi Brutus ,
i m dealing with the same issue now…can you please elabrate your solution…it would be really helpful for me … thanks a lot.


#9

I don’t have access to my code back then. But as a general solution try to wrap your variable in an ObjectValue. You can read up more in the docs here:
https://docs.camunda.org/manual/7.10/user-guide/process-engine/variables/#object-value-serialization


#10

Thanks a lot…
Cheers