wanglingsong/JsonSurfer

Improve filtering on objects (argument matching nested object)

Closed this issue ยท 6 comments

This is related to comparison test case https://cburgmer.github.io/json-path-comparison/results/filter_expression_after_recursive_descent.html#Java_com.github.jsurfer

Consider the following JSON:

[
  {"letter" : "A", "number": 1, "boolean": true},
  {"letter" : "B", "number": 2, "boolean": false, "next":  {"letter" : "X", "number": 1.1, "boolean": true } },
  {"letter" : "C", "number": 3, "boolean": true, "next":  {"letter" : "X", "number": 1.2, "boolean": false } },
  {"letter" : "D", "number": 4, "boolean": true, "next":  {"letter" : "X", "number": 1.3, "boolean": true } }
]

and the following Java snippet:

String expression = // The JsonPath expression
InputStream is = getClass().getClassLoader().getResourceAsStream("MultiJsonPath.json");
JsonSurfer surfer = new JsonSurfer(JacksonParser.INSTANCE, JacksonProvider.INSTANCE);
Collector collector = surfer.collector(is);
ValueBox<Collection<Object>> matches = collector.collectAll(expression);
collector.exec();

Iterator<Object> iter = matches.get().iterator();
while(iter.hasNext()){
	Object o = iter.next();
	System.err.println(o.getClass());
	if(o instanceof Map) {
		Iterator<Entry> iten = ((Map) o).entrySet().iterator();
		while (iten.hasNext()) {
			System.err.println(" > " + iten.next());
	    }
    }
}

I get the following behaviour with the path expressions

Expression: $..[?(@.letter == 'X')] (does not work as expected)

class java.util.LinkedHashMap
 > letter=B
 > number=2
 > boolean=false
 > next={letter=X, number=1.1, boolean=true}
class java.util.LinkedHashMap
 > letter=C
 > number=3
 > boolean=true
 > next={letter=X, number=1.2, boolean=false}
class java.util.LinkedHashMap
 > letter=D
 > number=4
 > boolean=true
 > next={letter=X, number=1.3, boolean=true}

I would have expected instead, matches of the inner JsonObjects only:

class java.util.LinkedHashMap
 > letter=X
 > number=1.1
 > boolean=true
class java.util.LinkedHashMap
 > letter=X
 > number=1.2
 > boolean=false
class java.util.LinkedHashMap
 > letter=X
 > number=1.3
 > boolean=true

Changing the expression to matching one object in the first 'layer' works as expected.

Expression $..[?(@.letter == 'A')] (works as expected)

class java.util.LinkedHashMap
 > letter=A
 > number=1
 > boolean=true

Expression $..[?(@.number == 1.2)] (does not work as expected)

class java.util.LinkedHashMap
 > letter=C
 > number=3
 > boolean=true
 > next={letter=X, number=1.2, boolean=false}

I think the problem is indeed the fact that the match is including the containing object, but it should not (at least, from my understanding of JsonPath). The behaviour I would have expected is the one of Jayway, I tried with https://jsonpath.herokuapp.com . However, I want to stick to JsonSurfer for the streaming capabilities.

For reference, the case is implemented as a test here and relates to this feature issue

Thanks so much for reporting. I'll examine the code to see if any quick fix on this.

@enridaga the first working implementation just submitted. Please feel free to pull the source and test

Works as expected now -- we may do more tests later but in the meantime this looks very good -- look forward to the release!

Any plan for the next release?

Any plan for the next release?

Merged in master

published