Skip to content

Commit

Permalink
Allow JsonNodeELResolver to invoke get and path with a long index (
Browse files Browse the repository at this point in the history
  • Loading branch information
rssap authored Jan 20, 2025
1 parent 143d03a commit a7b7bcf
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ public class JsonNodeELResolver extends ELResolver {
private final boolean readOnly;

/**
* Creates a new read/write BeanELResolver.
* Creates a new read/write JsonNodeELResolver.
*/
public JsonNodeELResolver() {
this(false);
}

/**
* Creates a new BeanELResolver whose read-only status is determined by the given parameter.
* Creates a new JsonNodeELResolver whose read-only status is determined by the given parameter.
*/
public JsonNodeELResolver(boolean readOnly) {
this.readOnly = readOnly;
Expand Down Expand Up @@ -257,6 +257,38 @@ public boolean isReadOnly(ELContext context, Object base, Object property) {
}
return readOnly;
}

@Override
public Object invoke(ELContext context, Object base, Object method, Class<?>[] paramTypes, Object[] params) {
if (!isResolvable(base)) {
return null;
}
if (method == null) {
return null;
}
if (params.length != 1) {
return null;
}
Object param = params[0];
if (!(param instanceof Long)) {
return null;
}

int index = ((Long) param).intValue();
String methodName = method.toString();
JsonNode node = (JsonNode) base;
if (methodName.equals("path")) {
JsonNode valueNode = node.path(index);
context.setPropertyResolved(true);
return valueNode;
} else if (methodName.equals("get")) {
JsonNode valueNode = node.get(index);
context.setPropertyResolved(true);
return valueNode;
}

return null;
}

/**
* 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
Expand Down Expand Up @@ -275,6 +276,66 @@ public void testInvokeIntegerMethodWithNullParameter() {
assertThat(value).isNull();
}

@Test
@Deployment(resources = "org/flowable/engine/test/api/runtime/oneTaskProcess.bpmn20.xml")
public void testInvokeOnArrayNode() {
Map<String, Object> vars = new HashMap<>();
ArrayNode arrayNode = processEngineConfiguration.getObjectMapper().createArrayNode();
arrayNode.add("firstValue");
arrayNode.add("secondValue");
arrayNode.add(42);

vars.put("array", arrayNode);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess", vars);

assertThat(getExpressionValue("${array.get(0).isTextual()}", processInstance)).isEqualTo(true);
assertThat(getExpressionValue("${array.get(0).textValue()}", processInstance)).isEqualTo("firstValue");
assertThat(getExpressionValue("${array.get(0).isNumber()}", processInstance)).isEqualTo(false);

assertThat(getExpressionValue("${array.get(2).isNumber()}", processInstance)).isEqualTo(true);
assertThat(getExpressionValue("${array.get(2).asInt()}", processInstance)).isEqualTo(42);
assertThat(getExpressionValue("${array.get(2).asLong()}", processInstance)).isEqualTo(42L);

assertThat(getExpressionValue("${array.get(1).textValue()}", processInstance)).isEqualTo("secondValue");
assertThat(getExpressionValue("${array.get(1).asLong(123)}", processInstance)).isEqualTo(123L);

assertThat(getExpressionValue("${array.get(3)}", processInstance)).isNull();
assertThat(getExpressionValue("${array.path(3).isMissingNode()}", processInstance)).isEqualTo(true);
}

@Test
@Deployment(resources = "org/flowable/engine/test/api/runtime/oneTaskProcess.bpmn20.xml")
public void testInvokeOnObjectNode() {
Map<String, Object> vars = new HashMap<>();
ObjectNode objectNode = processEngineConfiguration.getObjectMapper().createObjectNode();
objectNode.put("firstAttribute", "foo");
objectNode.put("secondAttribute", "bar");
objectNode.put("thirdAttribute", 42);

vars.put("object", objectNode);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess", vars);

assertThat(getExpressionValue("${object.get(\"firstAttribute\").isTextual()}", processInstance)).isEqualTo(true);
assertThat(getExpressionValue("${object.get(\"firstAttribute\").textValue()}", processInstance)).isEqualTo("foo");
assertThat(getExpressionValue("${object.get(\"firstAttribute\").isNumber()}", processInstance)).isEqualTo(false);

assertThat(getExpressionValue("${object.get(\"thirdAttribute\").isNumber()}", processInstance)).isEqualTo(true);
assertThat(getExpressionValue("${object.get(\"thirdAttribute\").asInt()}", processInstance)).isEqualTo(42);
assertThat(getExpressionValue("${object.get(\"thirdAttribute\").asLong()}", processInstance)).isEqualTo(42L);

assertThat(getExpressionValue("${object.get(\"secondAttribute\").textValue()}", processInstance)).isEqualTo("bar");
assertThat(getExpressionValue("${object.get(\"secondAttribute\").asLong(123)}", processInstance)).isEqualTo(123L);

assertThat(getExpressionValue("${object.get(\"dummyAttribute\")}", processInstance)).isNull();
assertThat(getExpressionValue("${object.path(\"dummyAttribute\").isMissingNode()}", processInstance)).isEqualTo(true);
}

private Object getExpressionValue(String expressionStr, ProcessInstance processInstance) {
Expression expression = this.processEngineConfiguration.getExpressionManager().createExpression(expressionStr);
return managementService.executeCommand(commandContext ->
expression.getValue((ExecutionEntity) runtimeService.createProcessInstanceQuery().processInstanceId(processInstance.getId()).includeProcessVariables().singleResult()));
}

@ParameterizedTest
@Deployment(resources = "org/flowable/engine/test/api/runtime/oneTaskProcess.bpmn20.xml")
@ValueSource(strings = { "", "flowable" })
Expand Down

0 comments on commit a7b7bcf

Please sign in to comment.