diff --git a/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateJsonPath.java b/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateJsonPath.java index b82764d3ff..fe89635dca 100644 --- a/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateJsonPath.java +++ b/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateJsonPath.java @@ -50,16 +50,17 @@ import java.util.*; @SideEffectFree @SupportsBatching @Tags({"JSON", "evaluate", "JsonPath"}) -@CapabilityDescription("Evaluates one or more JsonPath expressions against the content of a FlowFile. The results of those expressions are assigned to " - + "FlowFile Attributes or are written to the content of the FlowFile itself, depending on configuration of the " - + "Processor. JsonPaths are entered by adding user-defined properties; the name of the property maps to the Attribute " - + "Name into which the result will be placed (if the Destination is flowfile-attribute; otherwise, the property name is ignored). " - + "The value of the property must be a valid JsonPath expression. If the JsonPath evaluates to a JSON array or JSON object and the Return Type is " - + "set to 'scalar' the FlowFile will be unmodified and will be routed to failure. If the JsonPath does not " - + "evaluate to a scalar, the FlowFile will be routed to 'unmatched' without having its contents modified. If Destination is " - + "flowfile-attribute and the expression matches nothing, attributes will be created with empty strings as the value, and the " - + "FlowFile will always be routed to 'matched.' If Destination is 'flowfile-content' and the expression matches nothing, " - + "the FlowFile will be routed to 'unmatched' without having its contents modified.") +@CapabilityDescription("Evaluates one or more JsonPath expressions against the content of a FlowFile. " + + "The results of those expressions are assigned to FlowFile Attributes or are written to the content of the FlowFile itself, " + + "depending on configuration of the Processor. " + + "JsonPaths are entered by adding user-defined properties; the name of the property maps to the Attribute Name " + + "into which the result will be placed (if the Destination is flowfile-attribute; otherwise, the property name is ignored). " + + "The value of the property must be a valid JsonPath expression. " + + "If the JsonPath evaluates to a JSON array or JSON object and the Return Type is set to 'scalar' the FlowFile will be unmodified and will be routed to failure. " + + "A Return Type of JSON can return scalar values if the provided JsonPath evaluates to the specified value and will be routed as a match." + + "If Destination is 'flowfile-content' and the JsonPath does not evaluate to a defined path, the FlowFile will be routed to 'unmatched' without having its contents modified. " + + "If Destination is flowfile-attribute and the expression matches nothing, attributes will be created with " + + "empty strings as the value, and the FlowFile will always be routed to 'matched.'") public class EvaluateJsonPath extends AbstractProcessor { public static final String DESTINATION_ATTRIBUTE = "flowfile-attribute"; @@ -174,6 +175,7 @@ public class EvaluateJsonPath extends AbstractProcessor { } final String destination = processContext.getProperty(DESTINATION).getValue(); + final String returnType = processContext.getProperty(RETURN_TYPE).getValue(); flowFileLoop: for (FlowFile flowFile : flowFiles) { @@ -215,7 +217,6 @@ public class EvaluateJsonPath extends AbstractProcessor { final Map jsonPathResults = new HashMap<>(); - // Iterate through all JsonPath entries specified jsonPathEvalLoop: for (final Map.Entry attributeJsonPathEntry : attributeToJsonPathMap.entrySet()) { @@ -226,8 +227,9 @@ public class EvaluateJsonPath extends AbstractProcessor { final ObjectHolder resultHolder = new ObjectHolder<>(null); try { Object result = documentContext.read(jsonPathExp); - if (RETURN_TYPE.getName().equals(RETURN_TYPE_SCALAR) && !isScalar(result)) { - logger.error("Unable to return a scalar value for a JsonPath {} for FlowFile {}. Transferring to {}.", new Object[]{flowFile.getId(), jsonPathExp.getPath(), REL_FAILURE.getName()}); + if (returnType.equals(RETURN_TYPE_SCALAR) && !isScalar(result)) { + logger.error("Unable to return a scalar value for the expression {} for FlowFile {}. Evaluated value was {}. Transferring to {}.", + new Object[]{jsonPathExp.getPath(), flowFile.getId(), result.toString(), REL_FAILURE.getName()}); processSession.transfer(flowFile, REL_FAILURE); continue flowFileLoop; } @@ -273,9 +275,6 @@ public class EvaluateJsonPath extends AbstractProcessor { } private static boolean isScalar(Object obj) { - /* - * A given path could be a JSON object or a single/scalar value - */ return (obj instanceof String); } diff --git a/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateJsonPath.java b/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateJsonPath.java index e72d0690b7..c873969a7d 100644 --- a/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateJsonPath.java +++ b/nifi/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateJsonPath.java @@ -228,4 +228,23 @@ public class TestEvaluateJsonPath { testRunner.getFlowFilesForRelationship(expectedRel).get(0).assertContentEquals(JSON_SNIPPET); } + + @Test + public void testRouteFailure_returnTypeScalar_resultArray() throws Exception { + String jsonPathAttrKey = "friends.indefinite.id.list"; + + final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateJsonPath()); + testRunner.setProperty(EvaluateJsonPath.RETURN_TYPE, EvaluateJsonPath.RETURN_TYPE_SCALAR); + testRunner.setProperty(EvaluateJsonPath.DESTINATION, EvaluateJsonPath.DESTINATION_CONTENT); + testRunner.setProperty(jsonPathAttrKey, "$[0].friends[?(@.id < 3)].id"); + + testRunner.enqueue(JSON_SNIPPET); + testRunner.run(); + + Relationship expectedRel = EvaluateJsonPath.REL_FAILURE; + + testRunner.assertAllFlowFilesTransferred(expectedRel, 1); + testRunner.getFlowFilesForRelationship(expectedRel).get(0).assertContentEquals(JSON_SNIPPET); + } + }