如何为Camunda REST API创建List<Inventory>类型表单字段
解决Camunda FormField自定义List类型解析异常的方案
刚遇到这个问题的时候我也踩过坑——Camunda的内置表单字段类型确实不支持直接写List<org.example.Inventory>这种泛型自定义类,这就是你看到ENGINE-09005错误的核心原因。结合你偏好纯HTML表单、只用Camunda REST API的需求,给你两个可行的方案:
方案1:用String类型中转JSON(简单易上手)
因为Camunda能直接处理字符串变量,我们可以把Inventory列表转成JSON字符串提交,再在流程里解析成对象:
- 修改BPMN的formField配置:
把type设为string,给字段起个明确的ID,比如inventoriesJson:<userTask id="inventoryTask" name="Inventory Task"> <camunda:formFields> <camunda:formField id="inventoriesJson" label="Inventory Data" type="string" /> </camunda:formFields> </userTask> - HTML表单处理:
在你的HTML表单里,用JavaScript把要提交的Inventory数组转成JSON字符串,赋值给隐藏的表单字段(这种场景用隐藏域更合适,避免用户误编辑):<form id="inventoryForm"> <!-- 其他表单元素 --> <input type="hidden" name="inventoriesJson" id="inventoriesJson"> <button type="submit">Submit</button> </form> <script> // 假设你已经有了要提交的inventory数组 const inventories = [{"name": "banana","count": 3},{"name":"orange","count": 4}]; // 转成JSON字符串赋值给隐藏域 document.getElementById('inventoriesJson').value = JSON.stringify(inventories); // 提交表单到Camunda的submit-form接口 document.getElementById('inventoryForm').addEventListener('submit', async (e) => { e.preventDefault(); const formData = new FormData(e.target); const variables = Object.fromEntries(formData.entries()); const taskId = '你的任务ID'; // 替换成实际的任务ID await fetch(`/task/${taskId}/submit-form`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ variables }) }); }); </script> - 流程内解析JSON:
在流程的后续步骤(比如用ExecutionListener或者JavaDelegate)里,把字符串解析成List<Inventory>:import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.JavaDelegate; import java.util.List; public class ParseInventoryDelegate implements JavaDelegate { @Override public void execute(DelegateExecution execution) throws Exception { String json = (String) execution.getVariable("inventoriesJson"); ObjectMapper mapper = new ObjectMapper(); // 注意这里要和你的JSON字段对应,或者给Inventory类加@JsonProperty注解 List<Inventory> inventories = mapper.readValue(json, new TypeReference<List<Inventory>>(){}); execution.setVariable("inventories", inventories); } }
方案2:用generic类型直接映射(更优雅)
Camunda的generic类型支持自定义复杂对象,只要配置正确的类型信息,就能直接把提交的JSON数组映射成List<Inventory>:
- 修改BPMN的formField配置:
把type设为generic,并通过property指定valueType为你的泛型类型(注意XML里要转义<为<):<userTask id="inventoryTask" name="Inventory Task"> <camunda:formFields> <camunda:formField id="inventories" label="Inventory List" type="generic"> <camunda:properties> <camunda:property name="valueType" value="java.util.List<org.example.Inventory>" /> </camunda:properties> </camunda:formField> </camunda:formFields> </userTask> - 调整JSON字段名匹配:
你提交的JSON里用的是name和count,但你的Inventory类字段是objectName和objectCount,这会导致映射失败。解决方法二选一:- 把提交的JSON改成
{"objectName": "banana","objectCount": 3}; - 给
Inventory类的字段加Jackson的@JsonProperty注解,对应JSON的键:import com.fasterxml.jackson.annotation.JsonProperty; public class Inventory { @JsonProperty("name") private String objectName; @JsonProperty("count") private int objectCount; // getters and setters }
- 把提交的JSON改成
- HTML表单提交:
直接按照你原来的格式提交JSON到/task/{id}/submit-form接口即可,Camunda的REST API会自动帮你把JSON数组转成List<Inventory>变量:<form id="inventoryForm"> <button type="submit">Submit</button> </form> <script> document.getElementById('inventoryForm').addEventListener('submit', async (e) => { e.preventDefault(); const taskId = '你的任务ID'; const payload = { "inventories" : [{"name": "banana","count": 3},{"name":"orange","count": 4}] }; await fetch(`/task/${taskId}/submit-form`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); }); </script>
关键注意点
- 确保
Inventory类在Camunda的类路径下:如果是把Camunda Engine嵌入你的REST应用,只要你的Inventory类在应用的classpath里就没问题;如果是独立的Camunda服务器,需要把包含Inventory类的JAR包放到Camunda的lib目录下。 - 序列化兼容性:
Inventory类需要有默认无参构造器,并且getter/setter方法完整,这样Camunda的ObjectMapper才能正确序列化/反序列化。
内容的提问来源于stack exchange,提问作者niceman
相关产品推荐
相关产品推荐

