json-path / JsonPath

Java JsonPath implementation
Apache License 2.0
8.86k stars 1.64k forks source link

Deep scan with length function modifies document context #881

Open saimonsez opened 1 year ago

saimonsez commented 1 year ago

Reading twice from a DocumentContext should not modify its state, but that seems to be the case since 2.6.0.

Input:

{
  "a": "a",
  "b": "b",
  "c": "c",
  "d": {
    "e": [
      {
        "f": "f",
        "g": "g"
      }
    ]
  }
}

Test:

    @Test
    void deepScan() {
        String json = "{"
            + "  \"a\": \"a\","
            + "  \"b\": \"b\","
            + "  \"c\": \"c\","
            + "  \"d\": {"
            + "    \"e\": ["
            + "      {"
            + "        \"f\": \"f\","
            + "        \"g\": \"g\""
            + "      }"
            + "    ]"
            + "  }"
            + "}";
        final Configuration configuration = Configuration.defaultConfiguration();
        DocumentContext jsonDocument = JsonPath.using(configuration).parse(json);
        final Object result = jsonDocument.read("$..e.length()");
        final Object result2 = jsonDocument.read("$..e.length()");
        System.out.println(result);
        System.out.println(result2);
        // assertions ommited for issue
    }

Output: json-path 2.3.0 & 2.4.0: [1] [1]

json-path 2.5.0: 4 4

json-path 2.6.0 & 2.7.0: 1 2

json-path 2.5.0 seems to be broken, as it counts the elements a,b,c and d. json-path >= 2.6.0 fixed that, I guess.

However, with json-path 2.6.0 & 2.7.0 the second call to DocumentContext#read counts f and g (if the element g is removed, the result is 1 as expected).

fransonsr commented 1 year ago

I am seeing the same. json-path version: 2.7.0:

  @Test
  void length() {
    String json = """
      {
      "entry": [
            {
              "summary": "summary 5"
            },
            {
              "summary": "summary 3"
            },
            {
              "summary": "summary 7"
            },
            {
              "summary": "summary 1"
            }
          ]
      }
      """;

    ReadContext readContext = JsonPath.parse(json);
    for (int i = 0; i < 5; i++) {
      int length = readContext.read("$..entry.length()", Integer.class);
      System.out.println("length: " + length);
      if (length != 4) {
        throw new AssertionError("Length incorrect: " + length);
      }
    }
  }

With debug logging outputs the following:

13:15:19.958 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $.length()
13:15:19.972 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $..['entry']
13:15:19.972 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $..['entry'][*]
length: 4
13:15:19.974 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $.length()
13:15:19.975 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $..['entry'][*]
13:15:19.975 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $..['entry'][*][*]
length: 4
13:15:19.975 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $.length()
13:15:19.975 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $..['entry'][*][*]
13:15:19.975 [main] DEBUG com.jayway.jsonpath.internal.path.CompiledPath - Evaluating path: $..['entry'][*][*][*]
length: 0

java.lang.AssertionError: Length incorrect: 0

Note that the evaluated path goes deeper and deeper.