cancel
Showing results for 
Search instead for 
Did you mean: 

formProperty with default value saved to the database even though writable='false'

alexg
Champ in-the-making
Champ in-the-making
Hi all,

In my bpmn file I have a "status" formProperty declared as follows:


<userTask id="handleRequest" name="Handle request">
   <extensionElements>
      <activiti:formProperty id="requestApproved"
         name="Do you approve this request" type="enum" required="true">
         <activiti:value id="true" name="Approve" />
         <activiti:value id="false" name="Reject" />
      </activiti:formProperty>
      <activiti:formProperty id="status" name="Status"
         type="string" default="ACTIVE" readable="true" writable="false" />
   </extensionElements>
   <potentialOwner>
      <resourceAssignmentExpression>
         <formalExpression>approver</formalExpression>
      </resourceAssignmentExpression>
   </potentialOwner>
</userTask>


The call to formProperty.getValue() for "status" returns "ACTIVE" as expected:

final FormProperty formProperty = formService.getTaskFormData(task.getId()).getFormProperties().get(1);
final String value = formProperty.getValue();
assertEquals("ACTIVE", value);


But when I submit form data, the "status" variable gets created in the database and can be found in ACT_RU_VARIABLE table despite the writable="false" declaration:

formService.submitTaskFormData(task.getId(), Collections.singletonMap("requestApproved", (Object) "true"));


Documentation states that the property does not get submitted when declared non-writable, which means you would not expect it to be saved to the database. After all, there is an explicit check in the beginning of org.activiti.engine.impl.form.FormPropertyHandler.submitFormProperty() method:

if (!isWritable && properties.containsKey(id)) {
      throw new ActivitiException("form property '"+id+"' is not writable");
}


To my mind, the problem is that this method does not check isWritable flag before storing the variable to the database:

if (propertyExits || (modelValue != null)) {
      if (variableName != null) {
        execution.setVariable(variableName, modelValue);
      } else if (variableExpression != null) {
        variableExpression.setValue(modelValue, execution);
      } else {
        execution.setVariable(id, modelValue);
      }
}

It seems like isWritable should be checked in the final else, so you would have the following instead of the code above:

if (propertyExits || (modelValue != null)) {
      if (variableName != null) {
        execution.setVariable(variableName, modelValue);
      } else if (variableExpression != null) {
        variableExpression.setValue(modelValue, execution);
      } else if (isWritable) {
        execution.setVariable(id, modelValue);
      }
}


So is it a bug, or am I missing something?
2 REPLIES 2

martin_grofcik
Confirmed Champ
Confirmed Champ
Hi Alex.

I tried to debug it too. Values are stored in the database when there is
org.activiti.engine.form.FormProperty#isWritable
set to false.
java docs says:
/** Is this property expected when a user submits the form? */


I  used this jUnit test in 5.14

org.activiti.engine.test.api.form.FormServiceTest#testFormPropertyHandling


    try {
      properties = new HashMap<String, String>();
      properties.put("speaker", "its not allowed to update speaker!");
      formService.submitTaskFormData(taskId, properties);
      fail("expected exception about a non writable form property 'speaker'");
    } catch (ActivitiException e) {
      // OK
    }

where speaker is read only. This test passed. Speaker variable was set at formService.submitStartFormData(procDefId, properties)

I did not find test for default value.

alexg
Champ in-the-making
Champ in-the-making
Thank you, Martin. I should have provided the unit test for this to make the matter clear. What I mean is slightly different from what the above-mentioned code tests. I've attached the patch with the unit test and corresponding bpmn. The unit test fails exactly where I expect it to fail. The form property in question is "status" declared in "handleRequest" user task. Hope it helps.