diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java index 322a1719..1ce052da 100755 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java @@ -2,6 +2,7 @@ package com.jayway.jsonpath.internal.filter; import com.jayway.jsonpath.JsonPathException; import com.jayway.jsonpath.Predicate; +import com.jayway.jsonpath.internal.path.PredicateContextImpl; import java.util.HashMap; import java.util.Iterator; @@ -244,9 +245,25 @@ public class EvaluatorFactory { } private static class PredicateMatchEvaluator implements Evaluator { + /** + * Evaluate the match operation of predicate. + * + * @param left the ValueNode + * @param right the ValueNode + * @param ctx the PredicateContext + * @return boolean + */ @Override - public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { - return right.asPredicateNode().getPredicate().apply(ctx); + public boolean evaluate(final ValueNode left, final ValueNode right, final Predicate.PredicateContext ctx) { + // CS304 Issue link: https://github.com/json-path/JsonPath/issues/356 + // Create new predicateContext according to the left ValueNode + final Predicate.PredicateContext predicateContext = new PredicateContextImpl( + left.getValue(), + ctx.root(), + ctx.configuration(), + null + ); + return right.asPredicateNode().getPredicate().apply(predicateContext); //NOPMD - suppressed LawOfDemeter //NOPMD - suppressed LawOfDemeter } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java index cdf0dd97..b9ed24e8 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java @@ -16,6 +16,15 @@ public abstract class ValueNode { public abstract Class type(Predicate.PredicateContext ctx); + /** + * Get the value of ValueNode. + * The class of return Object depends on the type of ValueNode. + * + * @return Object + */ + // CS304 Issue link: https://github.com/json-path/JsonPath/issues/356 + public abstract Object getValue(); + public boolean isPatternNode() { return false; } @@ -157,6 +166,7 @@ public abstract class ValueNode { + //---------------------------------------------------- // // Factory methods diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java index 3f459a8c..07c25325 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java @@ -71,6 +71,11 @@ public interface ValueNodes { return Void.TYPE; } + @Override + public Object getValue() { + return compiledPattern; + } + public boolean isPatternNode() { return true; } @@ -125,6 +130,11 @@ public interface ValueNodes { else return Void.class; } + @Override + public Object getValue() { + return json; + } + public boolean isJsonNode() { return true; } @@ -248,6 +258,11 @@ public interface ValueNodes { return String.class; } + @Override + public Object getValue() { + return string; + } + public boolean isStringNode() { return true; } @@ -301,6 +316,11 @@ public interface ValueNodes { return Number.class; } + @Override + public Object getValue() { + return number; + } + public boolean isNumberNode() { return true; } @@ -357,6 +377,11 @@ public interface ValueNodes { return OffsetDateTimeNode.class; } + @Override + public Object getValue() { + return dateTime; + } + public boolean isOffsetDateTimeNode() { return true; } @@ -393,6 +418,11 @@ public interface ValueNodes { return Boolean.class; } + @Override + public Object getValue() { + return value; + } + public boolean isBooleanNode() { return true; } @@ -437,6 +467,11 @@ public interface ValueNodes { return Class.class; } + @Override + public Object getValue() { + return clazz; + } + public boolean isClassNode() { return true; } @@ -474,6 +509,11 @@ public interface ValueNodes { return Void.class; } + @Override + public Object getValue() { + return null; + } + @Override public boolean isNullNode() { return true; @@ -505,6 +545,11 @@ public interface ValueNodes { return Void.class; } + @Override + public Object getValue() { + return null; + } + public UndefinedNode asUndefinedNode() { return this; } @@ -540,6 +585,11 @@ public interface ValueNodes { return Void.class; } + @Override + public Object getValue() { + return predicate; + } + public boolean isPredicateNode() { return true; } @@ -587,6 +637,12 @@ public interface ValueNodes { return List.class; } + @Override + public Object getValue() { + List valueNodes = new ArrayList<>(nodes); + return valueNodes; + } + public boolean isValueListNode() { return true; } @@ -656,6 +712,11 @@ public interface ValueNodes { return Void.class; } + @Override + public Object getValue() { + return path; + } + public boolean isPathNode() { return true; } diff --git a/json-path/src/test/java/com/jayway/jsonpath/Issue_356.java b/json-path/src/test/java/com/jayway/jsonpath/Issue_356.java new file mode 100644 index 00000000..8601dfcf --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/Issue_356.java @@ -0,0 +1,91 @@ +// CS304 (manually written) +// Issue link: https://github.com/json-path/JsonPath/issues/356 +package com.jayway.jsonpath; + +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.LinkedHashMap; + +import static com.jayway.jsonpath.Criteria.where; +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test for issue 356 + */ +public class Issue_356 { //NOPMD - suppressed AtLeastOneConstructor //NOPMD - suppressed ClassNamingConventions + /** + * The json data for testing + */ + private static final String JSON = "{\n" + + " \"store\": {\n" + + " \"book\": [\n" + + " {\n" + + " \"title\": \"Sayings of the Century\",\n" + + " \"price\": {\n" + + " \"value\": 8.95,\n" + + " \"currency\": \"usd\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"title\": \"Sword of Honour\",\n" + + " \"price\": {\n" + + " \"value\": 12.99,\n" + + " \"currency\": \"usd\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"title\": \"Moby Dick\",\n" + + " \"price\": {\n" + + " \"value\": 8.99,\n" + + " \"currency\": \"usd\"\n" + + " }\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + /** + * The constraint for testing + */ + private static final double CONSTRAINT = 9; + + /** + * test1 for "...price.value" PredicateContext, + * it will return the book with the price value less than 9 + */ + @Test + public void test1() { + final Object ans = JsonPath.parse(JSON).read("$..book[?]", Filter.filter(where("price.value").matches(new Predicate() { //NOPMD - suppressed DataflowAnomalyAnalysis + @Override + public boolean apply(final PredicateContext ctx) { + // some custom logic with expecting value number in context + return ((BigDecimal) ctx.item()).doubleValue() < CONSTRAINT; + } + }))); + assertThat(ans.toString().equals("[{\"title\":\"Sayings of the Century\"," //NOPMD - suppressed LawOfDemeter + + "\"price\":{\"value\":8.95,\"currency\":\"usd\"}}," + + "{\"title\":\"Moby Dick\"," + + "\"price\":{\"value\":8.99,\"currency\":\"usd\"}}]")).isTrue(); + } + + + /** + * test2 for "...price" PredicateContext, + * it will return the book with the price value less than 9 + */ + @Test + public void test2() { + final Object ans = JsonPath.parse(JSON).read("$..book[?]", Filter.filter(where("price").matches(new Predicate() { //NOPMD - suppressed DataflowAnomalyAnalysis + @Override + public boolean apply(final PredicateContext ctx) { //NOPMD - suppressed CommentRequired + // some custom logic with expecting value number in context + return ((LinkedHashMap) ctx.item()).get("value") < CONSTRAINT; + } + }))); + assertThat(ans.toString().equals("[{\"title\":\"Sayings of the Century\"," //NOPMD - suppressed LawOfDemeter + + "\"price\":{\"value\":8.95,\"currency\":\"usd\"}}," + + "{\"title\":\"Moby Dick\"," + + "\"price\":{\"value\":8.99,\"currency\":\"usd\"}}]")).isTrue(); + } + +}