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

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


The following commit(s) were added to refs/heads/master by this push:
     new b06f9de  Use default values for null values when extracting with 
JSONPostProcessor
b06f9de is described below

commit b06f9def2a5c7007a6ee804487fc259c0fbd747b
Author: Felix Schumacher <[email protected]>
AuthorDate: Sat Nov 13 15:46:37 2021 +0100

    Use default values for null values when extracting with JSONPostProcessor
    
    When we extract a null value for a given expression, we now replace that
    null with the given default value for the expression.
    
    That leads to slight change of the meaning of a missing value.
    
    Consider the JSON structure: {"context": null} and the JSON Path: 
"$.context"
    
    The new implementation will replace the `null` with the default value, while
    the old would have stringified it to the empty string.
    
    Cleanup of parameter handling of default values. We should use the default
    value for the current handled expression and not pass all default values
    for all expression. That leads to confusion, only. (Well, I was confused)
    
    Bugzilla Id: 65681
---
 .../extractor/json/jsonpath/JSONManager.java       |  2 +-
 .../extractor/json/jsonpath/JSONPostProcessor.java | 51 +++++++++++-----------
 .../jmeter/extractor/TestJSONPostProcessor.java    | 25 ++++++++---
 xdocs/changes.xml                                  |  1 +
 4 files changed, 45 insertions(+), 34 deletions(-)

diff --git 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONManager.java
 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONManager.java
index f156f3d..c3f3371 100644
--- 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONManager.java
+++ 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONManager.java
@@ -95,7 +95,7 @@ public class JSONManager {
         if (obj instanceof JSONArray) {
             return ((JSONArray)obj).toJSONString();
         }
-        return obj == null ? "" : obj.toString(); //$NON-NLS-1$
+        return obj == null ? null : obj.toString();
     }
 
 }
diff --git 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
index 3e7c5cf..a20ea14 100644
--- 
a/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
+++ 
b/src/components/src/main/java/org/apache/jmeter/extractor/json/jsonpath/JSONPostProcessor.java
@@ -81,10 +81,10 @@ public class JSONPostProcessor
             clearOldRefVars(vars, currentRefName);
             try {
                 if (jsonResponses.isEmpty()) {
-                    handleEmptyResponse(vars, defaultValues, i, 
currentRefName);
+                    handleEmptyResponse(vars, defaultValues[i], 
currentRefName);
                 } else {
                     List<Object> extractedValues = 
extractValues(jsonResponses, currentJsonPath);
-                    handleResult(vars, defaultValues, i, matchNumber, 
currentRefName, extractedValues);
+                    handleResult(vars, defaultValues[i], matchNumber, 
currentRefName, extractedValues);
                 }
             } catch (Exception e) {
                 if (log.isDebugEnabled()) {
@@ -98,13 +98,13 @@ public class JSONPostProcessor
         }
     }
 
-    private void handleResult(JMeterVariables vars, String[] defaultValues, 
int i, int matchNumber,
-            String currentRefName, List<Object> extractedValues) {
+    private void handleResult(JMeterVariables vars, String defaultValue, int 
matchNumber, String currentRefName,
+            List<Object> extractedValues) {
         // if no values extracted, default value added
         if (extractedValues.isEmpty()) {
-            handleEmptyResult(vars, defaultValues, i, matchNumber, 
currentRefName);
+            handleEmptyResult(vars, defaultValue, matchNumber, currentRefName);
         } else {
-            handleNonEmptyResult(vars, defaultValues, i, matchNumber, 
currentRefName, extractedValues);
+            handleNonEmptyResult(vars, defaultValue, matchNumber, 
currentRefName, extractedValues);
         }
     }
 
@@ -116,14 +116,14 @@ public class JSONPostProcessor
         return extractedValues;
     }
 
-    private void handleNonEmptyResult(JMeterVariables vars, String[] 
defaultValues, int i, int matchNumber,
-            String currentRefName, List<Object> extractedValues) {
+    private void handleNonEmptyResult(JMeterVariables vars, String 
defaultValue, int matchNumber, String currentRefName,
+            List<Object> extractedValues) {
         // if more than one value extracted, suffix with "_index"
         if (extractedValues.size() > 1) {
-            handleListResult(vars, defaultValues, i, matchNumber, 
currentRefName, extractedValues);
+            handleListResult(vars, defaultValue, matchNumber, currentRefName, 
extractedValues);
         } else {
             // else just one value extracted
-            handleSingleResult(vars, matchNumber, currentRefName, 
extractedValues);
+            handleSingleResult(vars, defaultValue, matchNumber, 
currentRefName, extractedValues);
         }
         if (matchNumber != 0) {
             vars.put(currentRefName + REF_MATCH_NR, 
Integer.toString(extractedValues.size()));
@@ -142,17 +142,17 @@ public class JSONPostProcessor
         }
     }
 
-    private void handleSingleResult(JMeterVariables vars, final int 
matchNumber, String currentRefName,
+    private void handleSingleResult(JMeterVariables vars, String defaultValue, 
 final int matchNumber, String currentRefName,
             List<Object> extractedValues) {
         String suffix = (matchNumber < 0) ? "_1" : "";
-        placeObjectIntoVars(vars, currentRefName + suffix, extractedValues, 0);
+        placeObjectIntoVars(vars, currentRefName + suffix, extractedValues, 0, 
defaultValue);
         if (matchNumber < 0 && getComputeConcatenation()) {
             vars.put(currentRefName + ALL_SUFFIX, vars.get(currentRefName + 
suffix));
         }
     }
 
-    private void handleListResult(JMeterVariables vars, String[] 
defaultValues, final int i, final int matchNumber,
-            String currentRefName, List<Object> extractedValues) {
+    private void handleListResult(JMeterVariables vars, String defaultValue, 
final int matchNumber, String currentRefName,
+            List<Object> extractedValues) {
         if (matchNumber < 0) {
             // Extract all
             int index = 1;
@@ -161,7 +161,7 @@ public class JSONPostProcessor
                             ? extractedValues.size() * 20
                             : 1);
             for (Object extractedObject : extractedValues) {
-                String extractedString = stringify(extractedObject);
+                String extractedString = 
StringUtils.defaultString(stringify(extractedObject), defaultValue);
                 vars.put(currentRefName + "_" + index,
                         extractedString); //$NON-NLS-1$
                 if (getComputeConcatenation()) {
@@ -181,7 +181,7 @@ public class JSONPostProcessor
             int matchSize = extractedValues.size();
             int matchNr = JMeterUtils.getRandomInt(matchSize);
             placeObjectIntoVars(vars, currentRefName,
-                    extractedValues, matchNr);
+                    extractedValues, matchNr, defaultValue);
             return;
         }
         // extract at position
@@ -191,15 +191,14 @@ public class JSONPostProcessor
                     "matchNumber({}) exceeds number of items found({}), 
default value will be used",
                         matchNumber, extractedValues.size());
             }
-            vars.put(currentRefName, defaultValues[i]);
+            vars.put(currentRefName, defaultValue);
         } else {
-            placeObjectIntoVars(vars, currentRefName, extractedValues, 
matchNumber - 1);
+            placeObjectIntoVars(vars, currentRefName, extractedValues, 
matchNumber - 1, defaultValue);
         }
     }
 
-    private void handleEmptyResult(JMeterVariables vars, String[] 
defaultValues, int i, int matchNumber,
-            String currentRefName) {
-        vars.put(currentRefName, defaultValues[i]);
+    private void handleEmptyResult(JMeterVariables vars, String defaultValue, 
int matchNumber, String currentRefName) {
+        vars.put(currentRefName, defaultValue);
         vars.put(currentRefName + REF_MATCH_NR, "0"); //$NON-NLS-1$
         if (matchNumber < 0 && getComputeConcatenation()) {
             log.debug("No value extracted, storing empty in: {}{}", 
currentRefName, ALL_SUFFIX);
@@ -207,11 +206,11 @@ public class JSONPostProcessor
         }
     }
 
-    private void handleEmptyResponse(JMeterVariables vars, String[] 
defaultValues, int i, String currentRefName) {
+    private void handleEmptyResponse(JMeterVariables vars, String 
defaultValue, String currentRefName) {
         if(log.isDebugEnabled()) {
             log.debug("Response or source variable is null or empty for {}", 
getName());
         }
-        vars.put(currentRefName, defaultValues[i]);
+        vars.put(currentRefName, defaultValue);
     }
 
     private List<String> extractJsonResponse(JMeterContext context, 
JMeterVariables vars) {
@@ -245,13 +244,13 @@ public class JSONPostProcessor
     }
 
     private void placeObjectIntoVars(JMeterVariables vars, String 
currentRefName,
-            List<Object> extractedValues, int matchNr) {
+            List<Object> extractedValues, int matchNr, String defaultValue) {
         vars.put(currentRefName,
-                stringify(extractedValues.get(matchNr)));
+                
StringUtils.defaultString(stringify(extractedValues.get(matchNr)), 
defaultValue));
     }
 
     private String stringify(Object obj) {
-        return obj == null ? "" : obj.toString(); //$NON-NLS-1$
+        return obj == null ? null : obj.toString();
     }
 
     public String getJsonPathExpressions() {
diff --git 
a/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
 
b/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
index 57362dd..891a849 100644
--- 
a/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
+++ 
b/src/components/src/test/java/org/apache/jmeter/extractor/TestJSONPostProcessor.java
@@ -212,25 +212,36 @@ class TestJSONPostProcessor {
         assertThat(vars.get("varname_2"), 
CoreMatchers.is(CoreMatchers.nullValue()));
     }
 
-    @Test
-    void testEmptyInput() throws ParseException {
+    private static Stream<Arguments> provideEmptyOrNullResultArgs() {
+        return Stream.of(
+                Arguments.of("{\"context\": null}", "$.context", "0", null, 
"NONE"), // bug 65681
+                Arguments.of("[{\"context\": null}, {\"context\": \"\"}]", 
"$[*].context", "1", "2", "NONE"),
+                Arguments.of("[{\"context\": null}, {\"context\": \"\"}]", 
"$[*].context", "2", "2", ""),
+                Arguments.of("{\"context\": \"\"}", "$.context", "0", null, 
""),
+                Arguments.of("", "$.context", "0", null, "NONE"));
+    }
+
+    @ParameterizedTest
+    @MethodSource("provideEmptyOrNullResultArgs")
+    void testEmptyOrNullResult(String contextValue, String jsonPath, String 
matchNumber, String expectedMatchNumber,
+            String expectedResult) throws ParseException {
         JMeterContext context = JMeterContextService.getContext();
-        JSONPostProcessor processor = setupProcessor(context, "0", false);
+        JSONPostProcessor processor = setupProcessor(context, matchNumber, 
false);
 
         SampleResult result = new SampleResult();
-        result.setResponseData("".getBytes(StandardCharsets.UTF_8));
+        result.setResponseData(contextValue.getBytes(StandardCharsets.UTF_8));
 
         JMeterVariables vars = new JMeterVariables();
         context.setVariables(vars);
         context.setPreviousResult(result);
 
-        processor.setJsonPathExpressions("$.context");
+        processor.setJsonPathExpressions(jsonPath);
         processor.setDefaultValues("NONE");
         processor.setScopeAll();
         processor.process();
 
-        assertThat(vars.get(VAR_NAME), CoreMatchers.is("NONE"));
-        assertThat(vars.get(VAR_NAME + "_matchNr"), CoreMatchers.nullValue());
+        assertThat(vars.get(VAR_NAME), CoreMatchers.is(expectedResult));
+        assertThat(vars.get(VAR_NAME + "_matchNr"), 
CoreMatchers.is(expectedMatchNumber));
         assertThat(vars.get(VAR_NAME + "_1"), 
CoreMatchers.is(CoreMatchers.nullValue()));
     }
 
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index 6451c54..661d2df 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -213,6 +213,7 @@ Summary
   <li><bug>65259</bug>JMESPathExtractor Attribute <code>Match No.</code> 
Required</li>
   <li><bug>65269</bug>JSON Extractor and JSON JMESPath Extractor ignore 
sub-samples</li>
   <li><bug>65352</bug>Warning logged when Boundary Extractor doesn't find any 
match</li>
+  <li><bug>65681</bug>Use default values for null values when extracting with 
JSONPostProcessor</li>
 </ul>
 
 <h3>Functions</h3>

Reply via email to