You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2019/09/11 15:14:28 UTC

[nifi] branch master updated: NIFI-6642 - JsonPath support for adding array element

This is an automated email from the ASF dual-hosted git repository.

mattyb149 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/master by this push:
     new 9ec6314  NIFI-6642 - JsonPath support for adding array element
9ec6314 is described below

commit 9ec6314687dfc78ff28566770777e5ec0544f238
Author: mans2singh <ma...@yahoo.com>
AuthorDate: Sat Sep 7 11:11:35 2019 -0400

    NIFI-6642 - JsonPath support for adding array element
    
    NIFI-6642 - Updated json file used in tests
    
    Clarified function doc
    
    Signed-off-by: Matthew Burgess <ma...@apache.org>
    
    This closes #3711
---
 .../language/antlr/AttributeExpressionLexer.g      |  1 +
 .../language/antlr/AttributeExpressionParser.g     |  2 +-
 .../language/compile/ExpressionCompiler.java       | 46 +++++++++++------
 .../evaluation/functions/JsonPathAddEvaluator.java | 37 ++++++++++++++
 .../evaluation/functions/JsonPathSetEvaluator.java | 29 ++---------
 ...Evaluator.java => JsonPathUpdateEvaluator.java} | 21 ++++++--
 .../attribute/expression/language/TestQuery.java   | 34 +++++++++++++
 .../src/test/resources/json/address-book.json      |  3 +-
 .../main/asciidoc/expression-language-guide.adoc   | 58 +++++++++++++++++++++-
 9 files changed, 185 insertions(+), 46 deletions(-)

diff --git a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
index 0f93016..44fa387 100644
--- a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
+++ b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g
@@ -189,6 +189,7 @@ REPLACE_FIRST	: 'replaceFirst';
 REPLACE_ALL : 'replaceAll';
 IF_ELSE : 'ifElse';
 JSON_PATH_SET : 'jsonPathSet';
+JSON_PATH_ADD : 'jsonPathAdd';
 PAD_LEFT : 'padLeft';
 PAD_RIGHT : 'padRight';
 
diff --git a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
index 30576b7..6a62caa 100644
--- a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
+++ b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g
@@ -78,7 +78,7 @@ zeroArgString : (TO_UPPER | TO_LOWER | TRIM | TO_STRING | URL_ENCODE | URL_DECOD
 oneArgString : ((SUBSTRING_BEFORE | SUBSTRING_BEFORE_LAST | SUBSTRING_AFTER | SUBSTRING_AFTER_LAST | REPLACE_NULL | REPLACE_EMPTY |
 				PREPEND | APPEND | STARTS_WITH | ENDS_WITH | CONTAINS | JOIN | JSON_PATH | JSON_PATH_DELETE | FROM_RADIX) LPAREN! anyArg RPAREN!) |
 			   (TO_RADIX LPAREN! anyArg (COMMA! anyArg)? RPAREN!);
-twoArgString : ((REPLACE | REPLACE_FIRST | REPLACE_ALL | IF_ELSE | JSON_PATH_SET) LPAREN! anyArg COMMA! anyArg RPAREN!) |
+twoArgString : ((REPLACE | REPLACE_FIRST | REPLACE_ALL | IF_ELSE | JSON_PATH_SET | JSON_PATH_ADD) LPAREN! anyArg COMMA! anyArg RPAREN!) |
 			   ((SUBSTRING | FORMAT | PAD_LEFT | PAD_RIGHT) LPAREN! anyArg (COMMA! anyArg)? RPAREN!);
 fiveArgString : GET_DELIMITED_FIELD LPAREN! anyArg (COMMA! anyArg (COMMA! anyArg (COMMA! anyArg (COMMA! anyArg)?)?)?)? RPAREN!;
 
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
index 20b10d0..8edb832 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/compile/ExpressionCompiler.java
@@ -64,6 +64,7 @@ import org.apache.nifi.attribute.expression.language.evaluation.functions.InEval
 import org.apache.nifi.attribute.expression.language.evaluation.functions.IndexOfEvaluator;
 import org.apache.nifi.attribute.expression.language.evaluation.functions.IsEmptyEvaluator;
 import org.apache.nifi.attribute.expression.language.evaluation.functions.IsNullEvaluator;
+import org.apache.nifi.attribute.expression.language.evaluation.functions.JsonPathAddEvaluator;
 import org.apache.nifi.attribute.expression.language.evaluation.functions.JsonPathDeleteEvaluator;
 import org.apache.nifi.attribute.expression.language.evaluation.functions.JsonPathEvaluator;
 import org.apache.nifi.attribute.expression.language.evaluation.functions.JsonPathSetEvaluator;
@@ -180,6 +181,7 @@ import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpre
 import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.IS_NULL;
 import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.JOIN;
 import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.JSON_PATH;
+import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.JSON_PATH_ADD;
 import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.JSON_PATH_DELETE;
 import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.JSON_PATH_SET;
 import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.LAST_INDEX_OF;
@@ -952,27 +954,22 @@ public class ExpressionCompiler {
             }
             case JSON_PATH_SET: {
                 verifyArgCount(argEvaluators, 2, "jsonPathSet");
-                Evaluator<?> valueEvaluator = null;
                 Evaluator<?> argValueEvaluator = argEvaluators.get(1);
                 String location = "second argument to jsonPathSet";
-                if (argValueEvaluator instanceof StringEvaluator) {
-                    valueEvaluator = toStringEvaluator(argValueEvaluator, location);
-                } else if (argValueEvaluator instanceof DecimalEvaluator) {
-                    valueEvaluator = toDecimalEvaluator(argValueEvaluator, location);
-                } else if (argValueEvaluator instanceof NumberEvaluator) {
-                    valueEvaluator = toNumberEvaluator(argValueEvaluator, location);
-                } else if (argValueEvaluator instanceof WholeNumberEvaluator) {
-                    valueEvaluator = toWholeNumberEvaluator(argValueEvaluator, location);
-                } else if (argValueEvaluator instanceof BooleanEvaluator) {
-                    valueEvaluator = toBooleanEvaluator(argValueEvaluator, location);
-                } else {
-                    throw new AttributeExpressionLanguageParsingException("Cannot implicitly convert Data Type " +
-                            argValueEvaluator.getResultType() + (location == null ? "" : " at location [" + location + "]"));
-                }
+                Evaluator<?> valueEvaluator = getJsonPathUpdateEvaluator(argValueEvaluator, location);
                 return addToken(new JsonPathSetEvaluator(toStringEvaluator(subjectEvaluator),
                         toStringEvaluator(argEvaluators.get(0), "first argument to jsonPathSet"),
                         valueEvaluator), "jsonPathSet");
             }
+            case JSON_PATH_ADD: {
+                verifyArgCount(argEvaluators, 2, "jsonPathAdd");
+                Evaluator<?> argValueEvaluator = argEvaluators.get(1);
+                String location = "second argument to jsonPathAdd";
+                Evaluator<?> valueEvaluator = getJsonPathUpdateEvaluator(argValueEvaluator, location);
+                return addToken(new JsonPathAddEvaluator(toStringEvaluator(subjectEvaluator),
+                        toStringEvaluator(argEvaluators.get(0), "first argument to jsonPathAdd"),
+                        valueEvaluator), "jsonPathAdd");
+            }
             case IF_ELSE: {
                 verifyArgCount(argEvaluators, 2, "ifElse");
                 return addToken(new IfElseEvaluator(toBooleanEvaluator(subjectEvaluator),
@@ -984,6 +981,25 @@ public class ExpressionCompiler {
         }
     }
 
+    private Evaluator<?> getJsonPathUpdateEvaluator(Evaluator<?> argValueEvaluator, String location) {
+        Evaluator<?> valueEvaluator;
+        if (argValueEvaluator instanceof StringEvaluator) {
+            valueEvaluator = toStringEvaluator(argValueEvaluator, location);
+        } else if (argValueEvaluator instanceof DecimalEvaluator) {
+            valueEvaluator = toDecimalEvaluator(argValueEvaluator, location);
+        } else if (argValueEvaluator instanceof NumberEvaluator) {
+            valueEvaluator = toNumberEvaluator(argValueEvaluator, location);
+        } else if (argValueEvaluator instanceof WholeNumberEvaluator) {
+            valueEvaluator = toWholeNumberEvaluator(argValueEvaluator, location);
+        } else if (argValueEvaluator instanceof BooleanEvaluator) {
+            valueEvaluator = toBooleanEvaluator(argValueEvaluator, location);
+        } else {
+            throw new AttributeExpressionLanguageParsingException("Cannot implicitly convert Data Type " +
+                    argValueEvaluator.getResultType() + (location == null ? "" : " at location [" + location + "]"));
+        }
+        return valueEvaluator;
+    }
+
     public Evaluator<?> buildEvaluator(final Tree tree) {
         switch (tree.getType()) {
             case EXPRESSION: {
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathAddEvaluator.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathAddEvaluator.java
new file mode 100644
index 0000000..05638c7
--- /dev/null
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathAddEvaluator.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.attribute.expression.language.evaluation.functions;
+
+import com.jayway.jsonpath.DocumentContext;
+import com.jayway.jsonpath.JsonPath;
+import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
+
+/**
+ * JsonPathAddEvaluator allows adding a value to an array at the specified existing path
+ */
+public class JsonPathAddEvaluator extends JsonPathUpdateEvaluator {
+
+    public JsonPathAddEvaluator(final Evaluator<String> subject, final Evaluator<String> jsonPathExp, final Evaluator<?> valueEvaluator) {
+        super(subject, jsonPathExp, valueEvaluator);
+    }
+
+    @Override
+    public DocumentContext updateAttribute(DocumentContext documentContext, JsonPath jsonPath, Object value) {
+        return documentContext.add(jsonPath, value);
+    }
+}
+
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathSetEvaluator.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathSetEvaluator.java
index a7aead0..4289b5d 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathSetEvaluator.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathSetEvaluator.java
@@ -18,40 +18,21 @@ package org.apache.nifi.attribute.expression.language.evaluation.functions;
 
 import com.jayway.jsonpath.DocumentContext;
 import com.jayway.jsonpath.JsonPath;
-import org.apache.nifi.attribute.expression.language.EvaluationContext;
+
 import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
-import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
-import org.apache.nifi.attribute.expression.language.evaluation.StringQueryResult;
 
 /**
  * JsonPathSetEvaluator allows setting values at the specified existing path
  */
-public class JsonPathSetEvaluator extends JsonPathBaseEvaluator {
-
-    protected Evaluator<?> valueEvaluator;
+public class JsonPathSetEvaluator extends JsonPathUpdateEvaluator {
 
     public JsonPathSetEvaluator(final Evaluator<String> subject, final Evaluator<String> jsonPathExp, final Evaluator<?> valueEvaluator) {
-        super(subject, jsonPathExp);
-        this.valueEvaluator = valueEvaluator;
+        super(subject, jsonPathExp, valueEvaluator);
     }
 
     @Override
-    public QueryResult<String> evaluate(EvaluationContext context) {
-        DocumentContext documentContext = getDocumentContext(context);
-        final JsonPath compiledJsonPath = getJsonPath(context);
-
-        final Object value = valueEvaluator.evaluate(context).getValue();
-
-        String result;
-        try {
-            result = documentContext.set(compiledJsonPath, value).jsonString();
-        } catch (Exception e) {
-            // assume the path did not match anything in the document
-            return EMPTY_RESULT;
-        }
-
-        return new StringQueryResult(getResultRepresentation(result, EMPTY_RESULT.getValue()));
+    public DocumentContext updateAttribute(DocumentContext documentContext, JsonPath jsonPath, Object value) {
+        return documentContext.set(jsonPath, value);
     }
-
 }
 
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathSetEvaluator.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathUpdateEvaluator.java
similarity index 66%
copy from nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathSetEvaluator.java
copy to nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathUpdateEvaluator.java
index a7aead0..030271e 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathSetEvaluator.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/JsonPathUpdateEvaluator.java
@@ -22,15 +22,19 @@ import org.apache.nifi.attribute.expression.language.EvaluationContext;
 import org.apache.nifi.attribute.expression.language.evaluation.Evaluator;
 import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
 import org.apache.nifi.attribute.expression.language.evaluation.StringQueryResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
- * JsonPathSetEvaluator allows setting values at the specified existing path
+ * JsonPathUpdateEvaluator is base class for updating attributes
  */
-public class JsonPathSetEvaluator extends JsonPathBaseEvaluator {
+public abstract class JsonPathUpdateEvaluator extends JsonPathBaseEvaluator {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(JsonPathUpdateEvaluator.class);
 
     protected Evaluator<?> valueEvaluator;
 
-    public JsonPathSetEvaluator(final Evaluator<String> subject, final Evaluator<String> jsonPathExp, final Evaluator<?> valueEvaluator) {
+    public JsonPathUpdateEvaluator(final Evaluator<String> subject, final Evaluator<String> jsonPathExp, final Evaluator<?> valueEvaluator) {
         super(subject, jsonPathExp);
         this.valueEvaluator = valueEvaluator;
     }
@@ -44,8 +48,9 @@ public class JsonPathSetEvaluator extends JsonPathBaseEvaluator {
 
         String result;
         try {
-            result = documentContext.set(compiledJsonPath, value).jsonString();
+            result = updateAttribute(documentContext, compiledJsonPath, value).jsonString();
         } catch (Exception e) {
+            LOGGER.error("Failed to update attribute " + e.getLocalizedMessage(), e);
             // assume the path did not match anything in the document
             return EMPTY_RESULT;
         }
@@ -53,5 +58,13 @@ public class JsonPathSetEvaluator extends JsonPathBaseEvaluator {
         return new StringQueryResult(getResultRepresentation(result, EMPTY_RESULT.getValue()));
     }
 
+    /**
+     * Update the attribute at the specified path
+     * @param documentContext the document to be updated
+     * @param jsonPath the path to update
+     * @param value the value to be applied at the specified path
+     * @return the updated DocumentContext
+     */
+    public abstract DocumentContext updateAttribute(DocumentContext documentContext, JsonPath jsonPath, Object value);
 }
 
diff --git a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
index c45f7f5..e44e348 100644
--- a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
+++ b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java
@@ -17,6 +17,7 @@
 package org.apache.nifi.attribute.expression.language;
 
 import org.antlr.runtime.tree.Tree;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.attribute.expression.language.Query.Range;
 import org.apache.nifi.attribute.expression.language.evaluation.NumberQueryResult;
 import org.apache.nifi.attribute.expression.language.evaluation.QueryResult;
@@ -346,6 +347,10 @@ public class TestQuery {
 
     private void verifyAddressBookAttributes(String originalAddressBook, Map<String,String> attributes, String updatedAttribute, Object updatedValue) {
 
+        if (StringUtils.isBlank(attributes.get("json"))) {
+            throw new IllegalArgumentException("original Json attributes is empty");
+        }
+
         Map<String, String> originalAttributes = new HashMap<>();
         originalAttributes.put("json", originalAddressBook);
 
@@ -453,6 +458,35 @@ public class TestQuery {
     }
 
     @Test
+    public void testJsonPathAddNicknameJimmy() throws IOException {
+        Map<String,String> attributes = verifyJsonPathExpressions(
+                ADDRESS_BOOK_JSON_PATH_EMPTY,
+                "",
+                "${json:jsonPathAdd('$.nicknames', 'Jimmy')}",
+                "");
+        verifyEquals("${json:jsonPath('$.nicknames')}", attributes, "Jimmy");
+    }
+
+    @Test
+    public void testJsonPathAddNicknameJimmyAtNonexistantPath() throws IOException {
+        Map<String,String> attributes = verifyJsonPathExpressions(
+                ADDRESS_BOOK_JSON_PATH_EMPTY,
+                "",
+                "${json:jsonPathAdd('$.missing-path', 'Jimmy')}",
+                "");
+       verifyEquals("${json:jsonPath('$.missing-path')}", attributes, "");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void testJsonPathAddNicknameJimmyAtNonArray() throws IOException {
+        Map<String,String> attributes = verifyJsonPathExpressions(
+                ADDRESS_BOOK_JSON_PATH_EMPTY,
+                "",
+                "${json:jsonPathAdd('$.firstName', 'Jimmy')}",
+                "");
+    }
+
+    @Test
     public void testEmbeddedExpressionsAndQuotesWithProperties() {
         final Map<String, String> attributes = new HashMap<>();
         attributes.put("x", "abc");
diff --git a/nifi-commons/nifi-expression-language/src/test/resources/json/address-book.json b/nifi-commons/nifi-expression-language/src/test/resources/json/address-book.json
index 3f7981b..090bc42 100644
--- a/nifi-commons/nifi-expression-language/src/test/resources/json/address-book.json
+++ b/nifi-commons/nifi-expression-language/src/test/resources/json/address-book.json
@@ -19,5 +19,6 @@
              "type": "office", 
              "number": "646 555-4567"
          }
-     ]
+     ],
+     "nicknames" : []
  }
\ No newline at end of file
diff --git a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
index e85ed5d..7fa2fc4 100644
--- a/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/expression-language-guide.adoc
@@ -1699,6 +1699,61 @@ form of the updated JSON.#
 An empty subject value or a subject value with an invalid JSON document results in an exception bulletin.
 
 [.function]
+=== jsonPathAdd
+
+*Description*: [.description]#The `jsonPathAdd` function adds a scalar value to an array at the specified JsonPath on
+a Subject JSON and returns string form of the updated JSON.#  If the expression target element is a non-array,
+an empty string is returned and an exception is logged indicating the error.  If the expression target element
+path is not in the JSON, the operation returns the original JSON without any modifications.
+
+*Subject Type*: [.subject]#String#
+
+*Arguments*:
+
+- [.argName]#_jsonPath_# : [.argDesc]#the JSON path expression to set value on the Subject.#
+- [.argName]#_value_# : [.argDesc]#the value expression to be added to the array at the specified path on Subject.#
+
+*Return Type*: [.returnType]#String#
+
+*Examples*: If the "myJson" attribute is
+
+..........
+{
+     "firstName": "John",
+     "lastName": "Smith",
+     "age": 25,
+     "voter" : true,
+     "height" : 6.1,
+     "address" : {
+         "streetAddress": "21 2nd Street",
+         "city": "New York",
+         "state": "NY",
+         "postalCode": "10021-3100"
+     },
+     "phoneNumbers": [
+         {
+             "type": "home",
+             "number": "212 555-1234"
+         },
+         {
+             "type": "office",
+             "number": "646 555-4567"
+         }
+     ],
+     "nicknames" : []
+ }
+..........
+
+.jsonPathAdd Examples
+|===================================================================
+| Expression | Value
+| `${myJson:jsonPathAdd('$.nicknames', 'Jimmy')}` | `{"firstName":"James", lastName":"Smith", "age":25, "voter":true, "height":6.1, "address":{"streetAddress":"21 2nd Street", "city":"New York", "state":"NY", "postalCode":"10021-3100"}, "phoneNumbers":[{"type":"home", "number":"212 555-1234"}, {"type":"office", "number":"646 555-4567"}],"nicknames":["Jimmy"]}`
+| `${myJson:jsonPathAdd('$.missingpath', 'Jimmy')}` | Returns original JSON document with no modifications
+| `${myJson:jsonPathAdd('$.firstName', 'Jimmy')}` | _empty_
+|===================================================================
+
+
+[.function]
 === jsonPathSet
 
 *Description*: [.description]#The `jsonPathSet` function sets the value at the specified JsonPath on a Subject JSON and returns string
@@ -1737,7 +1792,8 @@ form of the updated JSON.#
              "type": "office",
              "number": "646 555-4567"
          }
-     ]
+     ],
+     "nicknames" : []
  }
 ..........