Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public String getPathFragment() {
return arrayIndexOperation.toString();
}

@Override
public boolean acceptsUpstreamArrayIndex(int index) {
return arrayIndexOperation.indexes().contains(index);
}

@Override
public boolean isTokenDefinite() {
return arrayIndexOperation.isSingleIndexOperation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ public void setUpstreamArrayIndex(int idx){
upstreamArrayIndex = idx;
}

/**
* Whether an array element at the given index, reached by a deep scan
* iterating an array, satisfies this token's own selection so that its
* leaf properties may contribute to the result. Only explicit array
* index tokens restrict the selection; wildcard, slice, scan, property
* and predicate tokens accept every element.
*/
public boolean acceptsUpstreamArrayIndex(int index) {
return true;
}

PathToken appendTailToken(PathToken next) {
this.next = next;
this.next.prev = this;
Expand Down Expand Up @@ -81,8 +92,10 @@ void handleObjectProperty(String currentPath, Object model, EvaluationContextImp
}
PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, property) : PathRef.NO_OP;
if (isLeaf()) {
String idx = "[" + String.valueOf(upstreamArrayIndex) + "]";
if(idx.equals("[-1]") || ctx.getRoot().getTail().prev().getPathFragment().equals(idx)){
// A token without a previous link is mounted by a function parameter
// evaluation (see Length), so there is no path constraint to apply
if (upstreamArrayIndex == -1 || prev() == null
|| prev().acceptsUpstreamArrayIndex(upstreamArrayIndex)) {
ctx.addResult(evalPath, pathRef, propertyVal);
}
}
Expand Down
60 changes: 60 additions & 0 deletions json-path/src/test/java/com/jayway/jsonpath/DeepScanTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,66 @@ public void when_deep_scanning_leaf_multi_props_work() {
}
}

@Test
public void when_deep_scanning_wildcard_before_leaf_property_works() {
Object result = JsonPath.parse(JSON_DOCUMENT).read("$..*.title");
assertThat(result).asList().containsExactly(
"Sayings of the Century", "Sword of Honour", "Moby Dick", "The Lord of the Rings");
}

@Test
public void when_deep_scanning_single_array_index_before_leaf_property_works() {
Object result = JsonPath.parse(JSON_DOCUMENT).read("$..[2].author");
assertThat(result).asList().containsExactly("Herman Melville");
}

@Test
public void when_deep_scanning_multiple_array_indexes_before_leaf_property_works() {
Object result = JsonPath.parse(JSON_DOCUMENT).read("$..[0,2].author");
assertThat(result).asList().containsExactly("Nigel Rees", "Herman Melville");
}

@Test
public void when_deep_scanning_function_parameter_with_scan_wildcard_does_not_throw() {
// $..* feeds Length through a wildcard that is mounted on the parameter
// path without a previous link; the leaf filter must not dereference it
// the function mounts its wildcard on the parameter path without a
// previous link, so the leaf filter must not dereference it; the
// values match the completed deep scan results after this fix
Object result = JsonPath.parse(JSON_DOCUMENT).read("$..*.length()");
assertThat(result).isEqualTo(31);

result = JsonPath.parse(JSON_DOCUMENT).read("$..[0].length()");
assertThat(result).isEqualTo(18);

result = JsonPath.parse(JSON_DOCUMENT).read("$..[*].length()");
assertThat(result).isEqualTo(31);
}

@Test
public void when_deep_scanning_double_wildcard_after_fix() {
// the same fix family: a wildcard fed by a deep scan used to drop
// every result, so the second wildcard received nothing
Object result = JsonPath.parse(JSON_DOCUMENT).read("$..*.*");
assertThat(result).asList().hasSize(31);
}

@Test
public void when_deep_scanning_slice_before_leaf_property_accepts_all_elements() {
// documented boundary: a slice upstream accepts every fed element, the
// exact [from,to) range would need the array length at the leaf
Object result = JsonPath.parse(JSON_DOCUMENT).read("$..[1:3].author");
assertThat(result).asList().containsExactly(
"Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien");
}

@Test
public void when_deep_scanning_negative_index_before_leaf_property_returns_empty() {
// pre-existing: negative indexes never match the fed element indexes
Object result = JsonPath.parse(JSON_DOCUMENT).read("$..[-1].author");
assertThat(result).asList().isEmpty();
}

@Test
public void require_single_property_ok() {

Expand Down