Browse Source

Fix #857 DCollecting all values for given key in object array returns empty Collection

pull/859/head
skwqy 2 years ago
parent
commit
5174797534
  1. 49
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java
  2. 28
      json-path/src/test/java/com/jayway/jsonpath/Issue_857.java

49
json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java

@ -32,7 +32,7 @@ public abstract class PathToken {
private int upstreamArrayIndex = -1; private int upstreamArrayIndex = -1;
public void setUpstreamArrayIndex(int idx){ public void setUpstreamArrayIndex(int idx) {
upstreamArrayIndex = idx; upstreamArrayIndex = idx;
} }
@ -44,32 +44,32 @@ public abstract class PathToken {
void handleObjectProperty(String currentPath, Object model, EvaluationContextImpl ctx, List<String> properties) { void handleObjectProperty(String currentPath, Object model, EvaluationContextImpl ctx, List<String> properties) {
if(properties.size() == 1) { if (properties.size() == 1) {
String property = properties.get(0); String property = properties.get(0);
String evalPath = Utils.concat(currentPath, "['", property, "']"); String evalPath = Utils.concat(currentPath, "['", property, "']");
Object propertyVal = readObjectProperty(property, model, ctx); Object propertyVal = readObjectProperty(property, model, ctx);
if(propertyVal == JsonProvider.UNDEFINED){ if (propertyVal == JsonProvider.UNDEFINED) {
// Conditions below heavily depend on current token type (and its logic) and are not "universal", // Conditions below heavily depend on current token type (and its logic) and are not "universal",
// so this code is quite dangerous (I'd rather rewrite it & move to PropertyPathToken and implemented // so this code is quite dangerous (I'd rather rewrite it & move to PropertyPathToken and implemented
// WildcardPathToken as a dynamic multi prop case of PropertyPathToken). // WildcardPathToken as a dynamic multi prop case of PropertyPathToken).
// Better safe than sorry. // Better safe than sorry.
assert this instanceof PropertyPathToken : "only PropertyPathToken is supported"; assert this instanceof PropertyPathToken : "only PropertyPathToken is supported";
if(isLeaf()) { if (isLeaf()) {
if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){ if (ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)) {
propertyVal = null; propertyVal = null;
} else { } else {
if(ctx.options().contains(Option.SUPPRESS_EXCEPTIONS) || if (ctx.options().contains(Option.SUPPRESS_EXCEPTIONS) ||
!ctx.options().contains(Option.REQUIRE_PROPERTIES)){ !ctx.options().contains(Option.REQUIRE_PROPERTIES)) {
return; return;
} else { } else {
throw new PathNotFoundException("No results for path: " + evalPath); throw new PathNotFoundException("No results for path: " + evalPath);
} }
} }
} else { } else {
if (! (isUpstreamDefinite() && isTokenDefinite()) && if (!(isUpstreamDefinite() && isTokenDefinite()) &&
!ctx.options().contains(Option.REQUIRE_PROPERTIES) || !ctx.options().contains(Option.REQUIRE_PROPERTIES) ||
ctx.options().contains(Option.SUPPRESS_EXCEPTIONS)){ ctx.options().contains(Option.SUPPRESS_EXCEPTIONS)) {
// If there is some indefiniteness in the path and properties are not required - we'll ignore // If there is some indefiniteness in the path and properties are not required - we'll ignore
// absent property. And also in case of exception suppression - so that other path evaluation // absent property. And also in case of exception suppression - so that other path evaluation
// branches could be examined. // branches could be examined.
@ -82,11 +82,11 @@ public abstract class PathToken {
PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, property) : PathRef.NO_OP; PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, property) : PathRef.NO_OP;
if (isLeaf()) { if (isLeaf()) {
String idx = "[" + String.valueOf(upstreamArrayIndex) + "]"; String idx = "[" + String.valueOf(upstreamArrayIndex) + "]";
if(idx.equals("[-1]") || ctx.getRoot().getTail().prev().getPathFragment().equals(idx)){ if (idx.equals("[-1]") || ctx.getRoot().getTail().prev().getPathFragment().equals(idx) ||
ctx.getRoot().getTail().prev().getPathFragment().equals("[*]")) {
ctx.addResult(evalPath, pathRef, propertyVal); ctx.addResult(evalPath, pathRef, propertyVal);
} }
} } else {
else {
next().evaluate(evalPath, pathRef, propertyVal, ctx); next().evaluate(evalPath, pathRef, propertyVal, ctx);
} }
} else { } else {
@ -97,17 +97,17 @@ public abstract class PathToken {
Object merged = ctx.jsonProvider().createMap(); Object merged = ctx.jsonProvider().createMap();
for (String property : properties) { for (String property : properties) {
Object propertyVal; Object propertyVal;
if(hasProperty(property, model, ctx)) { if (hasProperty(property, model, ctx)) {
propertyVal = readObjectProperty(property, model, ctx); propertyVal = readObjectProperty(property, model, ctx);
if(propertyVal == JsonProvider.UNDEFINED){ if (propertyVal == JsonProvider.UNDEFINED) {
if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)) { if (ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)) {
propertyVal = null; propertyVal = null;
} else { } else {
continue; continue;
} }
} }
} else { } else {
if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){ if (ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)) {
propertyVal = null; propertyVal = null;
} else if (ctx.options().contains(Option.REQUIRE_PROPERTIES)) { } else if (ctx.options().contains(Option.REQUIRE_PROPERTIES)) {
throw new PathNotFoundException("Missing property in path " + evalPath); throw new PathNotFoundException("Missing property in path " + evalPath);
@ -146,7 +146,7 @@ public abstract class PathToken {
} }
} }
PathToken prev(){ PathToken prev() {
return prev; return prev;
} }
@ -162,7 +162,7 @@ public abstract class PathToken {
} }
boolean isRoot() { boolean isRoot() {
return prev == null; return prev == null;
} }
boolean isUpstreamDefinite() { boolean isUpstreamDefinite() {
@ -176,7 +176,7 @@ public abstract class PathToken {
int cnt = 1; int cnt = 1;
PathToken token = this; PathToken token = this;
while (!token.isLeaf()){ while (!token.isLeaf()) {
token = token.next(); token = token.next();
cnt++; cnt++;
} }
@ -184,7 +184,7 @@ public abstract class PathToken {
} }
public boolean isPathDefinite() { public boolean isPathDefinite() {
if(definite != null){ if (definite != null) {
return definite.booleanValue(); return definite.booleanValue();
} }
boolean isDefinite = isTokenDefinite(); boolean isDefinite = isTokenDefinite();
@ -214,11 +214,12 @@ public abstract class PathToken {
return super.equals(obj); return super.equals(obj);
} }
public void invoke(PathFunction pathFunction, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) { public void invoke(PathFunction pathFunction, String currentPath, PathRef parent, Object model,
EvaluationContextImpl ctx) {
ctx.addResult(currentPath, parent, pathFunction.invoke(currentPath, parent, model, ctx, null)); ctx.addResult(currentPath, parent, pathFunction.invoke(currentPath, parent, model, ctx, null));
} }
public abstract void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx); public abstract void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx);
public abstract boolean isTokenDefinite(); public abstract boolean isTokenDefinite();

28
json-path/src/test/java/com/jayway/jsonpath/Issue_857.java

@ -0,0 +1,28 @@
package com.jayway.jsonpath;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
/**
* @author skwqyg
* @Created on 2022 09 2022/9/10 16:36
*/
public class Issue_857 extends BaseTest{
@Test
public void test(){
Collection values = JsonPath.parse("[{\"key\":\"first value\"},{\"key\":\"second value\"}]")
.read("$..[*].key", java.util.Collection.class);
Assert.assertEquals(2,values.size());
Set<String> expect = new HashSet<>();
expect.add("first value");
expect.add("second value");
Assert.assertTrue(expect.containsAll(values));
System.out.println(values);
}
}
Loading…
Cancel
Save