Browse Source

Relaxed scanning with REQUIRE_PROPERTIES option.

pull/158/head
Kalle Stenflo 9 years ago
parent
commit
0fdc030c8a
  1. 20
      json-path/src/main/java/com/jayway/jsonpath/internal/path/ScanPathToken.java
  2. 1
      json-path/src/test/java/com/jayway/jsonpath/Configurations.java
  3. 131
      json-path/src/test/java/com/jayway/jsonpath/DeepScanTest.java
  4. 1
      json-path/src/test/resources/simplelogger.properties

20
json-path/src/main/java/com/jayway/jsonpath/internal/path/ScanPathToken.java

@ -111,7 +111,7 @@ public class ScanPathToken extends PathToken {
return ".."; return "..";
} }
private static interface Predicate { private interface Predicate {
boolean matches(Object model); boolean matches(Object model);
} }
@ -170,15 +170,23 @@ public class ScanPathToken extends PathToken {
@Override @Override
public boolean matches(Object model) { public boolean matches(Object model) {
if (! ctx.jsonProvider().isMap(model)) { if (! ctx.jsonProvider().isMap(model)) {
return false; return false;
} }
if (ctx.options().contains(Option.REQUIRE_PROPERTIES)) { //
// Have to require properties defined in path when an indefinite path is evaluated, // The commented code below makes it really hard understand, use and predict the result
// so have to go there and search for it. // of deep scanning operations. It might be correct but was decided to be
return true; // left out until the behavior of REQUIRE_PROPERTIES is more strictly defined
} // in a deep scanning scenario. For details read conversation in commit
// https://github.com/jayway/JsonPath/commit/1a72fc078deb16995e323442bfb681bd715ce45a#commitcomment-14616092
//
// if (ctx.options().contains(Option.REQUIRE_PROPERTIES)) {
// // Have to require properties defined in path when an indefinite path is evaluated,
// // so have to go there and search for it.
// return true;
// }
if (! propertyPathToken.isTokenDefinite()) { if (! propertyPathToken.isTokenDefinite()) {
// It's responsibility of PropertyPathToken code to handle indefinite scenario of properties, // It's responsibility of PropertyPathToken code to handle indefinite scenario of properties,

1
json-path/src/test/java/com/jayway/jsonpath/Configurations.java

@ -54,7 +54,6 @@ public class Configurations {
); );
} }
public static Iterable<Configuration> objectMappingConfigurations() { public static Iterable<Configuration> objectMappingConfigurations() {
return Arrays.asList( return Arrays.asList(
GSON_CONFIGURATION GSON_CONFIGURATION

131
json-path/src/test/java/com/jayway/jsonpath/DeepScanTest.java

@ -7,6 +7,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static com.jayway.jsonpath.JsonPath.parse;
import static com.jayway.jsonpath.JsonPath.using; import static com.jayway.jsonpath.JsonPath.using;
import static com.jayway.jsonpath.TestUtils.assertEvaluationThrows; import static com.jayway.jsonpath.TestUtils.assertEvaluationThrows;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
@ -81,17 +82,25 @@ public class DeepScanTest extends BaseTest {
} }
@Test @Test
public void when_deep_scanning_require_properties_still_counts() { public void when_deep_scanning_require_properties_is_ignored_on_scan_target() {
final Configuration conf = Configuration.defaultConfiguration().addOptions(Option.REQUIRE_PROPERTIES); final Configuration conf = Configuration.defaultConfiguration().addOptions(Option.REQUIRE_PROPERTIES);
Object result = JsonPath.parse("[{\"x\": {\"foo\": {\"x\": 4}, \"x\": null}, \"y\": {\"x\": 1}}, {\"x\": []}]").read( Object result = JsonPath.parse("[{\"x\": {\"foo\": {\"x\": 4}, \"x\": null}, \"y\": {\"x\": 1}}, {\"x\": []}]").read(
"$..x"); "$..x");
assertThat(result).asList().hasSize(5); assertThat(result).asList().hasSize(5);
// foo.bar must be found in every object node after deep scan (which is impossible)
// assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$..foo.bar", PathNotFoundException.class, conf);
assertEvaluationThrows("{\"foo\": {\"bar\": 4}, \"baz\": 2}", "$..['foo', 'baz']", PathNotFoundException.class, conf); List<Integer> result1 = JsonPath.using(conf).parse("{\"foo\": {\"bar\": 4}}").read("$..foo.bar");
assertThat(result1).containsExactly(4);
assertEvaluationThrows("{\"foo\": {\"baz\": 4}}", "$..foo.bar", PathNotFoundException.class, conf);
}
@Test
public void when_deep_scanning_require_properties_is_ignored_on_scan_target_but_not_on_children() {
final Configuration conf = Configuration.defaultConfiguration().addOptions(Option.REQUIRE_PROPERTIES);
assertEvaluationThrows("{\"foo\": {\"baz\": 4}}", "$..foo.bar", PathNotFoundException.class, conf);
} }
@Test @Test
@ -133,8 +142,8 @@ public class DeepScanTest extends BaseTest {
assertThat(result).asList().containsExactly("a0","a1"); assertThat(result).asList().containsExactly("a0","a1");
} }
@Test(expected = PathNotFoundException.class) @Test
public void require_single_property_fail() { public void require_single_property() {
List json = new ArrayList() {{ List json = new ArrayList() {{
add(singletonMap("a", "a0")); add(singletonMap("a", "a0"));
@ -143,11 +152,13 @@ public class DeepScanTest extends BaseTest {
Configuration configuration = JSON_SMART_CONFIGURATION.addOptions(Option.REQUIRE_PROPERTIES); Configuration configuration = JSON_SMART_CONFIGURATION.addOptions(Option.REQUIRE_PROPERTIES);
JsonPath.using(configuration).parse(json).read("$..a"); Object result = JsonPath.using(configuration).parse(json).read("$..a");
assertThat(result).asList().containsExactly("a0");
} }
@Test @Test
public void require_multi_property_ok() { public void require_multi_property_all_match() {
final Map ab = new HashMap(){{ final Map ab = new HashMap(){{
put("a", "aa"); put("a", "aa");
@ -166,8 +177,8 @@ public class DeepScanTest extends BaseTest {
assertThat(result).containsExactly(ab, ab); assertThat(result).containsExactly(ab, ab);
} }
@Test(expected = PathNotFoundException.class) @Test
public void require_multi_property_fail() { public void require_multi_property_some_match() {
final Map ab = new HashMap(){{ final Map ab = new HashMap(){{
put("a", "aa"); put("a", "aa");
@ -186,7 +197,105 @@ public class DeepScanTest extends BaseTest {
Configuration configuration = JSON_SMART_CONFIGURATION.addOptions(Option.REQUIRE_PROPERTIES); Configuration configuration = JSON_SMART_CONFIGURATION.addOptions(Option.REQUIRE_PROPERTIES);
JsonPath.using(configuration).parse(json).read("$..['a', 'b']"); List<Map<String, String>> result = JsonPath.using(configuration).parse(json).read("$..['a', 'b']");
assertThat(result).containsExactly(ab);
}
@Test
public void scan_for_single_property() {
final Map a = new HashMap(){{
put("a", "aa");
}};
final Map b = new HashMap(){{
put("b", "bb");
}};
final Map ab = new HashMap(){{
put("a", a);
put("b", b);
}};
final Map b_ab = new HashMap(){{
put("b", b);
put("ab", ab);
}};
List json = new ArrayList() {{
add(a);
add(b);
add(b_ab);
}};
assertThat(parse(json).read("$..['a']", List.class)).containsExactly("aa", a, "aa");
}
@Test
public void scan_for_property_path() {
final Map a = new HashMap(){{
put("a", "aa");
}};
final Map x = new HashMap(){{
put("x", "xx");
}};
final Map y = new HashMap(){{
put("a", x);
}};
final Map z = new HashMap(){{
put("z", y);
}};
List json = new ArrayList() {{
add(a);
add(x);
add(y);
add(z);
}};
assertThat(parse(json).read("$..['a'].x", List.class)).containsExactly("xx", "xx");
}
@Test
public void scan_for_property_path_missing_required_property() {
final Map a = new HashMap(){{
put("a", "aa");
}};
final Map x = new HashMap(){{
put("x", "xx");
}};
final Map y = new HashMap(){{
put("a", x);
}};
final Map z = new HashMap(){{
put("z", y);
}};
List json = new ArrayList() {{
add(a);
add(x);
add(y);
add(z);
}};
assertThat(using(JSON_SMART_CONFIGURATION.addOptions(Option.REQUIRE_PROPERTIES)).parse(json).read("$..['a'].x", List.class)).containsExactly("xx", "xx");
}
@Test
public void scans_can_be_filtered() {
final Map brown = singletonMap("val", "brown");
final Map white = singletonMap("val", "white");
final Map cow = new HashMap(){{
put("mammal", true);
put("color", brown);
}};
final Map dog = new HashMap(){{
put("mammal", true);
put("color", white);
}};
final Map frog = new HashMap(){{
put("mammal", false);
}};
List animals = new ArrayList() {{
add(cow);
add(dog);
add(frog);
}};
assertThat(using(JSON_SMART_CONFIGURATION.addOptions(Option.REQUIRE_PROPERTIES)).parse(animals).read("$..[?(@.mammal == true)].color", List.class)).containsExactly(brown, white);
} }
} }

1
json-path/src/test/resources/simplelogger.properties

@ -1,4 +1,5 @@
#org.slf4j.simpleLogger.log.com.jayway=debug #org.slf4j.simpleLogger.log.com.jayway=debug
#org.slf4j.simpleLogger.log.com.jayway.jsonpath.internal.filter=trace #org.slf4j.simpleLogger.log.com.jayway.jsonpath.internal.filter=trace
#org.slf4j.simpleLogger.log.com.jayway.jsonpath.internal.path.ScanPathToken=trace

Loading…
Cancel
Save