Skip to content

Commit a7b7bcf

Browse files
authored
Allow JsonNodeELResolver to invoke get and path with a long index (#3996)
1 parent 143d03a commit a7b7bcf

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/el/JsonNodeELResolver.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ public class JsonNodeELResolver extends ELResolver {
3939
private final boolean readOnly;
4040

4141
/**
42-
* Creates a new read/write BeanELResolver.
42+
* Creates a new read/write JsonNodeELResolver.
4343
*/
4444
public JsonNodeELResolver() {
4545
this(false);
4646
}
4747

4848
/**
49-
* Creates a new BeanELResolver whose read-only status is determined by the given parameter.
49+
* Creates a new JsonNodeELResolver whose read-only status is determined by the given parameter.
5050
*/
5151
public JsonNodeELResolver(boolean readOnly) {
5252
this.readOnly = readOnly;
@@ -257,6 +257,38 @@ public boolean isReadOnly(ELContext context, Object base, Object property) {
257257
}
258258
return readOnly;
259259
}
260+
261+
@Override
262+
public Object invoke(ELContext context, Object base, Object method, Class<?>[] paramTypes, Object[] params) {
263+
if (!isResolvable(base)) {
264+
return null;
265+
}
266+
if (method == null) {
267+
return null;
268+
}
269+
if (params.length != 1) {
270+
return null;
271+
}
272+
Object param = params[0];
273+
if (!(param instanceof Long)) {
274+
return null;
275+
}
276+
277+
int index = ((Long) param).intValue();
278+
String methodName = method.toString();
279+
JsonNode node = (JsonNode) base;
280+
if (methodName.equals("path")) {
281+
JsonNode valueNode = node.path(index);
282+
context.setPropertyResolved(true);
283+
return valueNode;
284+
} else if (methodName.equals("get")) {
285+
JsonNode valueNode = node.get(index);
286+
context.setPropertyResolved(true);
287+
return valueNode;
288+
}
289+
290+
return null;
291+
}
260292

261293
/**
262294
* If the base object is a map, attempts to set the value associated with the given key, as specified by the property argument. If the base is a Map, the propertyResolved property of the ELContext

modules/flowable-engine/src/test/java/org/flowable/engine/test/el/ExpressionManagerTest.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.junit.jupiter.params.ParameterizedTest;
3333
import org.junit.jupiter.params.provider.ValueSource;
3434

35+
import com.fasterxml.jackson.databind.node.ArrayNode;
3536
import com.fasterxml.jackson.databind.node.ObjectNode;
3637

3738
/**
@@ -275,6 +276,66 @@ public void testInvokeIntegerMethodWithNullParameter() {
275276
assertThat(value).isNull();
276277
}
277278

279+
@Test
280+
@Deployment(resources = "org/flowable/engine/test/api/runtime/oneTaskProcess.bpmn20.xml")
281+
public void testInvokeOnArrayNode() {
282+
Map<String, Object> vars = new HashMap<>();
283+
ArrayNode arrayNode = processEngineConfiguration.getObjectMapper().createArrayNode();
284+
arrayNode.add("firstValue");
285+
arrayNode.add("secondValue");
286+
arrayNode.add(42);
287+
288+
vars.put("array", arrayNode);
289+
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess", vars);
290+
291+
assertThat(getExpressionValue("${array.get(0).isTextual()}", processInstance)).isEqualTo(true);
292+
assertThat(getExpressionValue("${array.get(0).textValue()}", processInstance)).isEqualTo("firstValue");
293+
assertThat(getExpressionValue("${array.get(0).isNumber()}", processInstance)).isEqualTo(false);
294+
295+
assertThat(getExpressionValue("${array.get(2).isNumber()}", processInstance)).isEqualTo(true);
296+
assertThat(getExpressionValue("${array.get(2).asInt()}", processInstance)).isEqualTo(42);
297+
assertThat(getExpressionValue("${array.get(2).asLong()}", processInstance)).isEqualTo(42L);
298+
299+
assertThat(getExpressionValue("${array.get(1).textValue()}", processInstance)).isEqualTo("secondValue");
300+
assertThat(getExpressionValue("${array.get(1).asLong(123)}", processInstance)).isEqualTo(123L);
301+
302+
assertThat(getExpressionValue("${array.get(3)}", processInstance)).isNull();
303+
assertThat(getExpressionValue("${array.path(3).isMissingNode()}", processInstance)).isEqualTo(true);
304+
}
305+
306+
@Test
307+
@Deployment(resources = "org/flowable/engine/test/api/runtime/oneTaskProcess.bpmn20.xml")
308+
public void testInvokeOnObjectNode() {
309+
Map<String, Object> vars = new HashMap<>();
310+
ObjectNode objectNode = processEngineConfiguration.getObjectMapper().createObjectNode();
311+
objectNode.put("firstAttribute", "foo");
312+
objectNode.put("secondAttribute", "bar");
313+
objectNode.put("thirdAttribute", 42);
314+
315+
vars.put("object", objectNode);
316+
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess", vars);
317+
318+
assertThat(getExpressionValue("${object.get(\"firstAttribute\").isTextual()}", processInstance)).isEqualTo(true);
319+
assertThat(getExpressionValue("${object.get(\"firstAttribute\").textValue()}", processInstance)).isEqualTo("foo");
320+
assertThat(getExpressionValue("${object.get(\"firstAttribute\").isNumber()}", processInstance)).isEqualTo(false);
321+
322+
assertThat(getExpressionValue("${object.get(\"thirdAttribute\").isNumber()}", processInstance)).isEqualTo(true);
323+
assertThat(getExpressionValue("${object.get(\"thirdAttribute\").asInt()}", processInstance)).isEqualTo(42);
324+
assertThat(getExpressionValue("${object.get(\"thirdAttribute\").asLong()}", processInstance)).isEqualTo(42L);
325+
326+
assertThat(getExpressionValue("${object.get(\"secondAttribute\").textValue()}", processInstance)).isEqualTo("bar");
327+
assertThat(getExpressionValue("${object.get(\"secondAttribute\").asLong(123)}", processInstance)).isEqualTo(123L);
328+
329+
assertThat(getExpressionValue("${object.get(\"dummyAttribute\")}", processInstance)).isNull();
330+
assertThat(getExpressionValue("${object.path(\"dummyAttribute\").isMissingNode()}", processInstance)).isEqualTo(true);
331+
}
332+
333+
private Object getExpressionValue(String expressionStr, ProcessInstance processInstance) {
334+
Expression expression = this.processEngineConfiguration.getExpressionManager().createExpression(expressionStr);
335+
return managementService.executeCommand(commandContext ->
336+
expression.getValue((ExecutionEntity) runtimeService.createProcessInstanceQuery().processInstanceId(processInstance.getId()).includeProcessVariables().singleResult()));
337+
}
338+
278339
@ParameterizedTest
279340
@Deployment(resources = "org/flowable/engine/test/api/runtime/oneTaskProcess.bpmn20.xml")
280341
@ValueSource(strings = { "", "flowable" })

0 commit comments

Comments
 (0)