Browse Source

Merge 5fcde2a675 into 45333e0a31

pull/796/merge
Vaibhav Tuteja 1 year ago committed by GitHub
parent
commit
cd7f8e7ac4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 543
      json-path/src/main/java/com/jayway/jsonpath/Criteria.java
  2. 829
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java
  3. 32
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/RelationalOperator.java
  4. 15
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java
  5. 66
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java
  6. 265
      json-path/src/test/java/com/jayway/jsonpath/FilterParseTest.java

543
json-path/src/main/java/com/jayway/jsonpath/Criteria.java

@ -157,6 +157,94 @@ public class Criteria implements Predicate {
return this;
}
/**
* Creates a criterion using the <b>&ltall;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria ltall(Object... o) {
return ltall(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&ltall;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria ltall(Collection<?> c) {
this.criteriaType = RelationalOperator.LTALL;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&lteall;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria lteall(Object... o) {
return lteall(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&lteall;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria lteall(Collection<?> c) {
this.criteriaType = RelationalOperator.LTEALL;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&ltany;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria ltany(Object... o) {
return ltany(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&ltany;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria ltany(Collection<?> c) {
this.criteriaType = RelationalOperator.LTANY;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&lteany;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria lteany(Object... o) {
return lteany(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&lteany;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria lteany(Collection<?> c) {
this.criteriaType = RelationalOperator.LTEANY;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&lt;=</b> operator
*
@ -181,6 +269,94 @@ public class Criteria implements Predicate {
return this;
}
/**
* Creates a criterion using the <b>&gtall;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria gtall(Object... o) {
return gtall(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&gtall;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria gtall(Collection<?> c) {
this.criteriaType = RelationalOperator.GTALL;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&gteall;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria gteall(Object... o) {
return gteall(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&gteall;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria gteall(Collection<?> c) {
this.criteriaType = RelationalOperator.GTEALL;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&gtany;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria gtany(Object... o) {
return gtany(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&gtany;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria gtany(Collection<?> c) {
this.criteriaType = RelationalOperator.GTANY;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&gteany;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria gteany(Object... o) {
return gteany(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&gteany;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria gteany(Collection<?> c) {
this.criteriaType = RelationalOperator.GTEANY;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&gt;=</b> operator
*
@ -304,7 +480,7 @@ public class Criteria implements Predicate {
* @return the criteria
*/
public Criteria anyof(Object... o) {
return subsetof(Arrays.asList(o));
return anyof(Arrays.asList(o));
}
/**
@ -371,6 +547,371 @@ public class Criteria implements Predicate {
return this;
}
/**
* Creates a criterion using the <b>&dateeq;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria dateeq(Object o) {
this.criteriaType = RelationalOperator.DATEEQ;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&dayeq;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria dayeq(Object o) {
this.criteriaType = RelationalOperator.DAYEQ;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&montheq;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria montheq(Object o) {
this.criteriaType = RelationalOperator.MONTHEQ;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&yeareq;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria yeareq(Object o) {
this.criteriaType = RelationalOperator.YEAREQ;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&dayin;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria dayin(Object... o) {
return dayin(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&dayin;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria dayin(Collection<?> c) {
this.criteriaType = RelationalOperator.DAYIN;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&monthin;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria monthin(Object... o) {
return monthin(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&monthin;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria monthin(Collection<?> c) {
this.criteriaType = RelationalOperator.MONTHIN;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&yearin;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria yearin(Object... o) {
return yearin(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&yearin;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria yearin(Collection<?> c) {
this.criteriaType = RelationalOperator.YEARIN;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&before;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria before(Object o) {
this.criteriaType = RelationalOperator.BEFORE;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&after;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria after(Object o) {
this.criteriaType = RelationalOperator.AFTER;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&houreq;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria houreq(Object o) {
this.criteriaType = RelationalOperator.HOUREQ;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&hourin;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria hourin(Object... o) {
return hourin(Arrays.asList(o));
}
/**
* Creates a criterion using the <b>&hourin;</b> operator
*
* @param c
* @return the criteria
*/
public Criteria hourin(Collection<?> c) {
this.criteriaType = RelationalOperator.HOURIN;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&timebefore;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria timebefore(Object o) {
this.criteriaType = RelationalOperator.TIMEBEFORE;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&timeafter;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria timeafter(Object o) {
this.criteriaType = RelationalOperator.TIMEAFTER;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* The <code>allmatch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param o the values to match against
* @return the criteria
*/
public Criteria allmatch(Object... o) {
return allmatch(Arrays.asList(o));
}
/**
* The <code>allmatch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param c the values to match against
* @return the criteria
*/
public Criteria allmatch(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.ALLMATCH;
this.right = new ValueListNode(c);
return this;
}
/**
* The <code>anymatch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param o the values to match against
* @return the criteria
*/
public Criteria anymatch(Object... o) {
return anymatch(Arrays.asList(o));
}
/**
* The <code>anymatch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param c the values to match against
* @return the criteria
*/
public Criteria anymatch(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.ANYMATCH;
this.right = new ValueListNode(c);
return this;
}
/**
* The <code>nonematch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param o the values to match against
* @return the criteria
*/
public Criteria nonematch(Object... o) {
return nonematch(Arrays.asList(o));
}
/**
* The <code>nonematch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param c the values to match against
* @return the criteria
*/
public Criteria nonematch(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.NONEMATCH;
this.right = new ValueListNode(c);
return this;
}
/**
* The <code>exactmatch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param o the values to match against
* @return the criteria
*/
public Criteria exactmatch(Object... o) {
return exactmatch(Arrays.asList(o));
}
/**
* The <code>exactmatch</code> operator selects objects for which the specified field is
* an array whose elements comprise a subset of the set comprised by the elements of
* the specified array.
*
* @param c the values to match against
* @return the criteria
*/
public Criteria exactmatch(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.EXACTMATCH;
this.right = new ValueListNode(c);
return this;
}
/**
* Creates a criterion using the <b>&windowin;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria windowin(Object o) {
this.criteriaType = RelationalOperator.WINDOWIN;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&windowout;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria windowout(Object o) {
this.criteriaType = RelationalOperator.WINDOWOUT;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&windowtimein;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria windowtimein(Object o) {
this.criteriaType = RelationalOperator.WINDOWTIMEIN;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* Creates a criterion using the <b>&windowtimeout;</b> operator
*
* @param o
* @return the criteria
*/
public Criteria windowtimeout(Object o) {
this.criteriaType = RelationalOperator.WINDOWTIMEOUT;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* The <code>notcontains</code> operator asserts that the provided object is not contained
* in the result. The object that should contain the input can be either an object or a String.
*
* @param o that should not exists in given collection or
* @return the criteria
*/
public Criteria notcontains(Object o) {
this.criteriaType = RelationalOperator.NOTCONTAINS;
this.right = ValueNode.toValueNode(o);
return this;
}
/**
* The <code>size</code> operator matches:
* <p/>

829
json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java

@ -1,8 +1,16 @@
package com.jayway.jsonpath.internal.filter;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.Predicate;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Month;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -37,16 +45,46 @@ public class EvaluatorFactory {
evaluators.put(RelationalOperator.SUBSETOF, new SubsetOfEvaluator());
evaluators.put(RelationalOperator.ANYOF, new AnyOfEvaluator());
evaluators.put(RelationalOperator.NONEOF, new NoneOfEvaluator());
evaluators.put(RelationalOperator.GTALL, new GreaterThanAllEvaluator());
evaluators.put(RelationalOperator.GTEALL, new GreaterThanEqualsAllEvaluator());
evaluators.put(RelationalOperator.GTANY, new GreaterThanAnyEvaluator());
evaluators.put(RelationalOperator.GTEANY, new GreaterThanEqualsAnyEvaluator());
evaluators.put(RelationalOperator.LTALL, new LessThanAllEvaluator());
evaluators.put(RelationalOperator.LTEALL, new LessThanEqualsAllEvaluator());
evaluators.put(RelationalOperator.LTANY, new LessThanAnyEvaluator());
evaluators.put(RelationalOperator.LTEANY, new LessThanEqualsAnyEvaluator());
evaluators.put(RelationalOperator.DATEEQ, new DateMatchEvaluator());
evaluators.put(RelationalOperator.DAYEQ, new DayMatchEvaluator());
evaluators.put(RelationalOperator.DAYIN, new DayInEvaluator());
evaluators.put(RelationalOperator.MONTHEQ, new MonthMatchEvaluator());
evaluators.put(RelationalOperator.MONTHIN, new MonthInEvaluator());
evaluators.put(RelationalOperator.YEAREQ, new YearMatchEvaluator());
evaluators.put(RelationalOperator.YEARIN, new YearInEvaluator());
evaluators.put(RelationalOperator.BEFORE, new BeforeEvaluator());
evaluators.put(RelationalOperator.AFTER, new AfterEvaluator());
evaluators.put(RelationalOperator.HOUREQ, new HourMatchEvaluator());
evaluators.put(RelationalOperator.HOURIN, new HourInEvaluator());
evaluators.put(RelationalOperator.TIMEBEFORE, new TimeBeforeEvaluator());
evaluators.put(RelationalOperator.TIMEAFTER, new TimeAfterEvaluator());
evaluators.put(RelationalOperator.NOTCONTAINS, new NotContainsEvaluator());
evaluators.put(RelationalOperator.ALLMATCH, new AllMatchEvaluator());
evaluators.put(RelationalOperator.ANYMATCH, new AnyMatchEvaluator());
evaluators.put(RelationalOperator.NONEMATCH, new NoneMatchEvaluator());
evaluators.put(RelationalOperator.EXACTMATCH, new ExactMatchEvaluator());
evaluators.put(RelationalOperator.WINDOWIN, new WindowInEvaluator());
evaluators.put(RelationalOperator.WINDOWOUT, new WindowOutEvaluator());
evaluators.put(RelationalOperator.WINDOWTIMEIN, new WindowTimeInEvaluator());
evaluators.put(RelationalOperator.WINDOWTIMEOUT, new WindowTimeOutEvaluator());
}
public static Evaluator createEvaluator(RelationalOperator operator){
public static Evaluator createEvaluator(RelationalOperator operator) {
return evaluators.get(operator);
}
private static class ExistsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(!left.isBooleanNode() && !right.isBooleanNode()){
if (!left.isBooleanNode() && !right.isBooleanNode()) {
throw new JsonPathException("Failed to evaluate exists expression");
}
return left.asBooleanNode().getBoolean() == right.asBooleanNode().getBoolean();
@ -70,7 +108,7 @@ public class EvaluatorFactory {
private static class EqualsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(left.isJsonNode() && right.isJsonNode()){
if (left.isJsonNode() && right.isJsonNode()) {
return left.asJsonNode().equals(right.asJsonNode(), ctx);
} else {
return left.equals(right);
@ -81,7 +119,7 @@ public class EvaluatorFactory {
private static class TypeSafeEqualsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(!left.getClass().equals(right.getClass())){
if (!left.getClass().equals(right.getClass())) {
return false;
}
return evaluators.get(RelationalOperator.EQ).evaluate(left, right, ctx);
@ -98,70 +136,378 @@ public class EvaluatorFactory {
private static class LessThanEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(left.isNumberNode() && right.isNumberNode()){
if (left.isNumberNode() && right.isNumberNode()) {
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) < 0;
} if(left.isStringNode() && right.isStringNode()){
}
if (left.isStringNode() && right.isStringNode()) {
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) < 0;
} if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()){ //workaround for issue: https://github.com/json-path/JsonPath/issues/613
}
if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()) { //workaround for issue: https://github.com/json-path/JsonPath/issues/613
return left.asOffsetDateTimeNode().getDate().compareTo(right.asOffsetDateTimeNode().getDate()) < 0;
}
return false;
}
}
private static class LessThanAllEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
BigDecimal smallest = leftListNode.getNodes().stream().map(node ->
node.asNumberNode().getNumber()).min(Comparator.naturalOrder()).get();
return rightListNode.getNodes().stream().allMatch(node -> node.asNumberNode()
.getNumber().compareTo(smallest) < 0);
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class LessThanAnyEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
boolean res = false;
for (ValueNode field : leftListNode.getNodes()) {
for (ValueNode value : rightListNode.getNodes()) {
if (field.asNumberNode().getNumber().compareTo(value.asNumberNode().getNumber()) < 0) {
res = true;
break;
}
}
}
return res;
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class LessThanEqualsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(left.isNumberNode() && right.isNumberNode()){
if (left.isNumberNode() && right.isNumberNode()) {
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) <= 0;
} if(left.isStringNode() && right.isStringNode()){
}
if (left.isStringNode() && right.isStringNode()) {
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) <= 0;
} if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()){ //workaround for issue: https://github.com/json-path/JsonPath/issues/613
}
if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()) { //workaround for issue: https://github.com/json-path/JsonPath/issues/613
return left.asOffsetDateTimeNode().getDate().compareTo(right.asOffsetDateTimeNode().getDate()) <= 0;
}
return false;
}
}
private static class LessThanEqualsAllEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
BigDecimal smallest = leftListNode.getNodes().stream().map(node ->
node.asNumberNode().getNumber()).min(Comparator.naturalOrder()).get();
return rightListNode.getNodes().stream().allMatch(node -> node.asNumberNode()
.getNumber().compareTo(smallest) <= 0);
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class LessThanEqualsAnyEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
boolean res = false;
for (ValueNode field : leftListNode.getNodes()) {
for (ValueNode value : rightListNode.getNodes()) {
if (field.asNumberNode().getNumber().compareTo(value.asNumberNode().getNumber()) <= 0) {
res = true;
break;
}
}
}
return res;
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class GreaterThanEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(left.isNumberNode() && right.isNumberNode()){
if (left.isNumberNode() && right.isNumberNode()) {
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) > 0;
} else if(left.isStringNode() && right.isStringNode()){
} else if (left.isStringNode() && right.isStringNode()) {
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) > 0;
} else if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()){ //workaround for issue: https://github.com/json-path/JsonPath/issues/613
} else if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()) { //workaround for issue: https://github.com/json-path/JsonPath/issues/613
return left.asOffsetDateTimeNode().getDate().compareTo(right.asOffsetDateTimeNode().getDate()) > 0;
}
return false;
}
}
private static class GreaterThanAllEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
BigDecimal largest = leftListNode.getNodes().stream().map(node ->
node.asNumberNode().getNumber()).max(Comparator.naturalOrder()).get();
return rightListNode.getNodes().stream().allMatch(node -> node.asNumberNode()
.getNumber().compareTo(largest) < 0);
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class GreaterThanAnyEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
boolean res = false;
for (ValueNode field : leftListNode.getNodes()) {
for (ValueNode value : rightListNode.getNodes()) {
if (field.asNumberNode().getNumber().compareTo(value.asNumberNode().getNumber()) > 0) {
res = true;
break;
}
}
}
return res;
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class GreaterThanEqualsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(left.isNumberNode() && right.isNumberNode()){
if (left.isNumberNode() && right.isNumberNode()) {
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) >= 0;
} else if(left.isStringNode() && right.isStringNode()){
} else if (left.isStringNode() && right.isStringNode()) {
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) >= 0;
} else if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()){ //workaround for issue: https://github.com/json-path/JsonPath/issues/613
} else if (left.isOffsetDateTimeNode() && right.isOffsetDateTimeNode()) { //workaround for issue: https://github.com/json-path/JsonPath/issues/613
return left.asOffsetDateTimeNode().getDate().compareTo(right.asOffsetDateTimeNode().getDate()) >= 0;
}
return false;
}
}
private static class GreaterThanEqualsAllEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
BigDecimal largest = leftListNode.getNodes().stream().map(node ->
node.asNumberNode().getNumber()).max(Comparator.naturalOrder()).get();
return rightListNode.getNodes().stream().allMatch(node -> node.asNumberNode()
.getNumber().compareTo(largest) <= 0);
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class GreaterThanEqualsAnyEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode leftListNode = left.isValueListNode() ? left.asValueListNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (leftListNode == null) {
leftListNode = convertJsonNodeToListNode(left, ctx);
}
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
if (leftListNode.getNodes().get(0).isNumberNode() && rightListNode.getNodes().get(0).isNumberNode()) {
boolean res = false;
for (ValueNode field : leftListNode.getNodes()) {
for (ValueNode value : rightListNode.getNodes()) {
if (field.asNumberNode().getNumber().compareTo(value.asNumberNode().getNumber()) >= 0) {
res = true;
break;
}
}
}
return res;
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn = node.isNumberNode() || node.isStringNode() ?
new ValueListNode(Collections.singleton(node.asNumberNode())) :
node.asJsonNode().asValueListNode(ctx);
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class SizeEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if (! right.isNumberNode()) {
if (!right.isNumberNode()) {
return false;
}
int expectedSize = right.asNumberNode().getNumber().intValue();
if(left.isStringNode()){
if (left.isStringNode()) {
return left.asStringNode().length() == expectedSize;
} else if(left.isJsonNode()){
} else if (left.isJsonNode()) {
return left.asJsonNode().length(ctx) == expectedSize;
}
return false;
@ -171,9 +517,9 @@ public class EvaluatorFactory {
private static class EmptyEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(left.isStringNode()){
if (left.isStringNode()) {
return left.asStringNode().isEmpty() == right.asBooleanNode().getBoolean();
} else if(left.isJsonNode()){
} else if (left.isJsonNode()) {
return left.asJsonNode().isEmpty(ctx) == right.asBooleanNode().getBoolean();
}
return false;
@ -184,9 +530,9 @@ public class EvaluatorFactory {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode valueListNode;
if(right.isJsonNode()){
if (right.isJsonNode()) {
ValueNode vn = right.asJsonNode().asValueListNode(ctx);
if(vn.isUndefinedNode()){
if (vn.isUndefinedNode()) {
return false;
} else {
valueListNode = vn.asValueListNode();
@ -210,12 +556,12 @@ public class EvaluatorFactory {
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode requiredValues = right.asValueListNode();
if(left.isJsonNode()){
if (left.isJsonNode()) {
ValueNode valueNode = left.asJsonNode().asValueListNode(ctx); //returns UndefinedNode if conversion is not possible
if(valueNode.isValueListNode()){
if (valueNode.isValueListNode()) {
ValueListNode shouldContainAll = valueNode.asValueListNode();
for (ValueNode required : requiredValues) {
if(!shouldContainAll.contains(required)){
if (!shouldContainAll.contains(required)) {
return false;
}
}
@ -229,14 +575,29 @@ public class EvaluatorFactory {
private static class ContainsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(left.isStringNode() && right.isStringNode()){
if (left.isStringNode() && right.isStringNode()) {
return left.asStringNode().contains(right.asStringNode().getString());
} else if(left.isJsonNode()){
} else if (left.isJsonNode()) {
ValueNode valueNode = left.asJsonNode().asValueListNode(ctx);
if (valueNode.isUndefinedNode()) return false;
else {
return valueNode.asValueListNode().contains(right);
}
}
return false;
}
}
private static class NotContainsEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if (left.isStringNode() && right.isStringNode()) {
return !(left.asStringNode().contains(right.asStringNode().getString()));
} else if (left.isJsonNode()) {
ValueNode valueNode = left.asJsonNode().asValueListNode(ctx);
if(valueNode.isUndefinedNode()) return false;
if (valueNode.isUndefinedNode()) return false;
else {
boolean res = valueNode.asValueListNode().contains(right);
return res;
return !(valueNode.asValueListNode().contains(right));
}
}
return false;
@ -253,7 +614,7 @@ public class EvaluatorFactory {
private static class RegexpEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
if(!(left.isPatternNode() ^ right.isPatternNode())){
if (!(left.isPatternNode() ^ right.isPatternNode())) {
return false;
}
@ -307,33 +668,33 @@ public class EvaluatorFactory {
}
private static class SubsetOfEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode rightValueListNode;
if(right.isJsonNode()){
ValueNode vn = right.asJsonNode().asValueListNode(ctx);
if(vn.isUndefinedNode()){
return false;
} else {
rightValueListNode = vn.asValueListNode();
}
} else {
rightValueListNode = right.asValueListNode();
}
ValueListNode leftValueListNode;
if(left.isJsonNode()){
ValueNode vn = left.asJsonNode().asValueListNode(ctx);
if(vn.isUndefinedNode()){
return false;
} else {
leftValueListNode = vn.asValueListNode();
}
} else {
leftValueListNode = left.asValueListNode();
}
return leftValueListNode.subsetof(rightValueListNode);
}
}
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueListNode rightValueListNode;
if (right.isJsonNode()) {
ValueNode vn = right.asJsonNode().asValueListNode(ctx);
if (vn.isUndefinedNode()) {
return false;
} else {
rightValueListNode = vn.asValueListNode();
}
} else {
rightValueListNode = right.asValueListNode();
}
ValueListNode leftValueListNode;
if (left.isJsonNode()) {
ValueNode vn = left.asJsonNode().asValueListNode(ctx);
if (vn.isUndefinedNode()) {
return false;
} else {
leftValueListNode = vn.asValueListNode();
}
} else {
leftValueListNode = left.asValueListNode();
}
return leftValueListNode.subsetof(rightValueListNode);
}
}
private static class AnyOfEvaluator implements Evaluator {
@Override
@ -408,4 +769,354 @@ public class EvaluatorFactory {
return true;
}
}
private static class DateMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime compDate = left.asDateNode().getDate();
ZonedDateTime evalDate = right.asDateNode().getDate().withZoneSameLocal(compDate.getZone());
return compDate.toLocalDate().compareTo(evalDate.toLocalDate()) == 0;
}
}
private static class MonthMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
try {
ZonedDateTime compDate = left.asDateNode().getDate();
ZonedDateTime evalDate = right.asDateNode().getDate().withZoneSameLocal(compDate.getZone());
return compDate.getMonth().compareTo(evalDate.getMonth()) == 0;
} catch (InvalidPathException e) {
Month month;
if (right.isStringNode()) {
month = Month.valueOf(right.asStringNode().getString());
} else {
month = Month.of(right.asNumberNode().getNumber().intValue());
}
return left.asDateNode().getDate().getMonth() == month;
}
}
}
private static class MonthInEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueNodes.DateNode leftListNode = left.isDateNode() ? left.asDateNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
ZonedDateTime compDate = leftListNode.getDate();
int month = compDate.getMonthValue();
if (rightListNode.getNodes().get(0).isDateNode()) {
return rightListNode.getNodes().stream().anyMatch(node ->
node.asDateNode().getDate().withZoneSameLocal(compDate.getZone()).getMonthValue() == month);
} else if (rightListNode.getNodes().get(0).isStringNode()) {
return rightListNode.getNodes().stream().anyMatch(node ->
Month.valueOf(node.asStringNode().getString()).getValue() == month);
} else if (rightListNode.getNodes().get(0).isNumberNode()) {
return rightListNode.getNodes().stream().anyMatch(node ->
Month.of(node.asNumberNode().getNumber().intValue()).getValue() == month);
}
return false;
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn;
try {
vn = new ValueListNode(Collections.singleton(node.asDateNode()));
} catch (InvalidPathException e) {
if (node.isStringNode()) {
vn = new ValueListNode(Collections.singleton(node.asStringNode()));
} else if (node.isJsonNode()) {
vn = node.asJsonNode().asValueListNode(ctx);
} else {
vn = new ValueListNode(Collections.singleton(node.asNumberNode()));
}
}
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class DayMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
try {
ZonedDateTime compDate = left.asDateNode().getDate();
ZonedDateTime evalDate = right.asDateNode().getDate().withZoneSameLocal(compDate.getZone());
return compDate.getDayOfMonth() == evalDate.getDayOfMonth();
} catch (InvalidPathException e) {
return left.asDateNode().getDate().getDayOfMonth() == right.asNumberNode().getNumber().intValue();
}
}
}
private static class DayInEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueNodes.DateNode leftListNode = left.isDateNode() ? left.asDateNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
ZonedDateTime compDate = leftListNode.getDate();
int day = compDate.getDayOfMonth();
if (rightListNode.getNodes().get(0).isDateNode()) {
return rightListNode.getNodes().stream().anyMatch(node ->
node.asDateNode().getDate().withZoneSameLocal(compDate.getZone()).getDayOfMonth() == day);
}
return rightListNode.getNodes().stream()
.anyMatch(node -> node.asNumberNode().getNumber().intValue() == day);
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn;
try {
vn = new ValueListNode(Collections.singleton(node.asDateNode()));
} catch (InvalidPathException e) {
if (node.isStringNode()) {
vn = new ValueListNode(Collections.singleton(node.asStringNode()));
} else if (node.isJsonNode()) {
vn = node.asJsonNode().asValueListNode(ctx);
} else {
vn = new ValueListNode(Collections.singleton(node.asNumberNode()));
}
}
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class YearMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
try {
ZonedDateTime compDate = left.asDateNode().getDate();
ZonedDateTime evalDate = right.asDateNode().getDate().withZoneSameLocal(compDate.getZone());
return compDate.getYear() == evalDate.getYear();
} catch (InvalidPathException e) {
return left.asDateNode().getDate().getYear() == right.asNumberNode().getNumber().intValue();
}
}
}
private static class YearInEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueNodes.DateNode leftListNode = left.isDateNode() ? left.asDateNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
ZonedDateTime compDate = leftListNode.getDate();
int year = compDate.getYear();
if (rightListNode.getNodes().get(0).isDateNode()) {
return rightListNode.getNodes().stream().anyMatch(node ->
node.asDateNode().getDate().withZoneSameLocal(compDate.getZone()).getYear() == year);
}
return rightListNode.getNodes().stream()
.anyMatch(node -> node.asNumberNode().getNumber().intValue() == year);
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn;
try {
vn = new ValueListNode(Collections.singleton(node.asDateNode()));
} catch (InvalidPathException e) {
if (node.isStringNode()) {
vn = new ValueListNode(Collections.singleton(node.asStringNode()));
} else if (node.isJsonNode()) {
vn = node.asJsonNode().asValueListNode(ctx);
} else {
vn = new ValueListNode(Collections.singleton(node.asNumberNode()));
}
}
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class BeforeEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime compDate = left.asDateNode().getDate();
ZonedDateTime evalDate = right.asDateNode().getDate().withZoneSameLocal(compDate.getZone());
return compDate.isBefore(evalDate);
}
}
private static class AfterEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime compDate = left.asDateNode().getDate();
ZonedDateTime evalDate = right.asDateNode().getDate().withZoneSameLocal(compDate.getZone());
return compDate.isAfter(evalDate);
}
}
private static class HourMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
try {
ZonedDateTime compDate = left.asDateNode().getDate();
ZonedDateTime evalDate = right.asDateNode().getDate().withZoneSameLocal(compDate.getZone());
return compDate.getHour() == evalDate.getHour();
} catch (InvalidPathException e) {
return left.asDateNode().getDate().getHour() == right.asNumberNode().getNumber().intValue();
}
}
}
private static class HourInEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueNodes.DateNode leftListNode = left.isDateNode() ? left.asDateNode() : null;
ValueListNode rightListNode = right.isValueListNode() ? right.asValueListNode() : null;
if (rightListNode == null) {
rightListNode = convertJsonNodeToListNode(right, ctx);
}
if (leftListNode == null || rightListNode == null) {
return false;
}
ZonedDateTime compDate = leftListNode.getDate();
int hour = compDate.getHour();
if (rightListNode.getNodes().get(0).isDateNode()) {
return rightListNode.getNodes().stream().anyMatch(node ->
node.asDateNode().getDate().withZoneSameLocal(compDate.getZone()).getHour() == hour);
}
return rightListNode.getNodes().stream()
.anyMatch(node -> node.asNumberNode().getNumber().intValue() == hour);
}
private ValueListNode convertJsonNodeToListNode(ValueNode node, Predicate.PredicateContext ctx) {
ValueListNode valueListNode = null;
ValueNode vn;
try {
vn = new ValueListNode(Collections.singleton(node.asDateNode()));
} catch (InvalidPathException e) {
if (node.isStringNode()) {
vn = new ValueListNode(Collections.singleton(node.asStringNode()));
} else if (node.isJsonNode()) {
vn = node.asJsonNode().asValueListNode(ctx);
} else {
vn = new ValueListNode(Collections.singleton(node.asNumberNode()));
}
}
if (!vn.isUndefinedNode()) {
valueListNode = vn.asValueListNode();
}
return valueListNode;
}
}
private static class TimeBeforeEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime date = left.asDateNode().getDate();
String[] time = right.asStringNode().getString().split(":");
ZonedDateTime evalDate = date.with(LocalTime.of(Integer.parseInt(time[0]), Integer.parseInt(time[1])));
return date.isBefore(evalDate);
}
}
private static class TimeAfterEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime date = left.asDateNode().getDate();
String[] time = right.asStringNode().getString().split(":");
ZonedDateTime evalDate = date.with(LocalTime.of(Integer.parseInt(time[0]), Integer.parseInt(time[1])));
return date.isAfter(evalDate);
}
}
private static class AllMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
return evaluators.get(RelationalOperator.SUBSETOF).evaluate(right, left, ctx);
}
}
private static class AnyMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
return evaluators.get(RelationalOperator.ANYOF).evaluate(right, left, ctx);
}
}
private static class NoneMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
return evaluators.get(RelationalOperator.NONEOF).evaluate(right, left, ctx);
}
}
private static class ExactMatchEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
return evaluators.get(RelationalOperator.ALL).evaluate(right, left, ctx);
}
}
private static class WindowInEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime date = left.asDateNode().getDate();
ZonedDateTime now = ZonedDateTime.now(date.getZone());
int window = right.asNumberNode().getNumber().intValue();
LocalDate finalDate = now.toLocalDate().minusDays(window);
return date.toLocalDate().isAfter(finalDate);
}
}
private static class WindowOutEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime date = left.asDateNode().getDate();
ZonedDateTime now = ZonedDateTime.now(date.getZone());
int window = right.asNumberNode().getNumber().intValue();
LocalDate finalDate = date.toLocalDate().minusDays(window);
return finalDate.isAfter(now.toLocalDate());
}
}
private static class WindowTimeInEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime date = left.asDateNode().getDate();
ZonedDateTime now = ZonedDateTime.now(date.getZone());
int window = right.asNumberNode().getNumber().intValue();
ZonedDateTime finalDate = now.minusDays(window);
return date.isAfter(finalDate);
}
}
private static class WindowTimeOutEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ZonedDateTime date = left.asDateNode().getDate();
ZonedDateTime now = ZonedDateTime.now(date.getZone());
int window = right.asNumberNode().getNumber().intValue();
ZonedDateTime finalDate = date.minusDays(window);
return finalDate.isAfter(now);
}
}
}

32
json-path/src/main/java/com/jayway/jsonpath/internal/filter/RelationalOperator.java

@ -34,7 +34,37 @@ public enum RelationalOperator {
EMPTY("EMPTY"),
SUBSETOF("SUBSETOF"),
ANYOF("ANYOF"),
NONEOF("NONEOF");
NONEOF("NONEOF"),
GTALL("GTALL"),
GTEALL("GTEALL"),
GTANY("GTANY"),
GTEANY("GTEANY"),
LTALL("LTALL"),
LTEALL("LTEALL"),
LTANY("LTANY"),
LTEANY("LTEANY"),
DATEEQ("DATEEQ"),
MONTHEQ("MONTHEQ"),
DAYEQ("DAYEQ"),
YEAREQ("YEAREQ"),
MONTHIN("MONTHIN"),
DAYIN("DAYIN"),
YEARIN("YEARIN"),
BEFORE("BEFORE"),
AFTER("AFTER"),
HOUREQ("HOUREQ"),
HOURIN("HOURIN"),
TIMEBEFORE("TIMEBEFORE"),
TIMEAFTER("TIMEAFTER"),
NOTCONTAINS("NOTCONTAINS"),
ALLMATCH("ALLMATCH"),
ANYMATCH("ANYMATCH"),
NONEMATCH("NONEMATCH"),
EXACTMATCH("EXACTMATCH"),
WINDOWIN("WINDOWIN"),
WINDOWOUT("WINDOWOUT"),
WINDOWTIMEIN("WINDOWTIMEIN"),
WINDOWTIMEOUT("WINDOWTIMEOUT");
private final String operatorString;

15
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java

@ -8,6 +8,8 @@ import com.jayway.jsonpath.internal.path.PathCompiler;
import net.minidev.json.parser.JSONParser;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;
import static com.jayway.jsonpath.internal.filter.ValueNodes.*;
@ -113,6 +115,13 @@ public abstract class ValueNode {
throw new InvalidPathException("Expected offsetDateTime node");
}
public boolean isDateNode(){
return false;
}
public DateNode asDateNode(){
throw new InvalidPathException("Expected date node");
}
private static boolean isPath(Object o) {
if(o == null || !(o instanceof String)){
@ -163,7 +172,7 @@ public abstract class ValueNode {
//
//----------------------------------------------------
public static ValueNode toValueNode(Object o){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss VV");
if(o == null) return NULL_NODE;
if(o instanceof ValueNode) return (ValueNode)o;
if(o instanceof Class) return createClassNode((Class)o);
@ -175,6 +184,7 @@ public abstract class ValueNode {
else if(o instanceof Boolean) return createBooleanNode(o.toString());
else if(o instanceof Pattern) return createPatternNode((Pattern)o);
else if (o instanceof OffsetDateTime) return createOffsetDateTimeNode(o.toString()); //workaround for issue: https://github.com/json-path/JsonPath/issues/613
else if (o instanceof ZonedDateTime) return createDateNode(((ZonedDateTime) o).format(formatter));
else throw new JsonPathException("Could not determine value type");
}
@ -220,6 +230,9 @@ public abstract class ValueNode {
return new OffsetDateTimeNode(charSequence);
}
public static DateNode createDateNode(String date) {
return new DateNode(date);
}
public static UndefinedNode createUndefinedNode() {
return UNDEFINED;

66
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java

@ -2,14 +2,12 @@ package com.jayway.jsonpath.internal.filter;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.*;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.Utils;
import com.jayway.jsonpath.internal.path.PathCompiler;
@ -227,6 +225,17 @@ public interface ValueNodes {
return new NumberNode(number);
}
@Override
public DateNode asDateNode() {
DateNode node;
try {
node = new DateNode(string);
} catch (IllegalArgumentException e) {
throw new InvalidPathException("Expected Timestamp format: dd MMM yyyy HH:mm:ss VV");
}
return node;
}
public String getString() {
return string;
}
@ -379,7 +388,54 @@ public interface ValueNodes {
}
}
class DateNode extends ValueNode {
private final ZonedDateTime dateTime;
private final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm:ss VV");
DateNode(ZonedDateTime dateTime) {
this.dateTime = dateTime;
}
DateNode(String date) {
dateTime = ZonedDateTime.parse(date, formatter);
}
@Override
public StringNode asStringNode() {
return new StringNode(dateTime.format(formatter), false);
}
public ZonedDateTime getDate() {
return dateTime;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return DateNode.class;
}
public boolean isDateNode() {
return true;
}
public DateNode asDateNode() {
return this;
}
@Override
public String toString() {
return dateTime.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof OffsetDateTimeNode) && !(o instanceof StringNode)) return false;
DateNode that = ((ValueNode) o).asDateNode();
return dateTime.compareTo(that.dateTime) == 0;
}
}
class BooleanNode extends ValueNode {
private final Boolean value;

265
json-path/src/test/java/com/jayway/jsonpath/FilterParseTest.java

@ -91,6 +91,34 @@ public class FilterParseTest {
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_ltall_filter_can_be_serialized() {
String filter = filter(where("a").ltall(1)).toString();
String parsed = parse("[?(@['a'] LTALL [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_lteall_filter_can_be_serialized() {
String filter = filter(where("a").lteall(1)).toString();
String parsed = parse("[?(@['a'] LTEALL [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_ltany_filter_can_be_serialized() {
String filter = filter(where("a").ltany(1)).toString();
String parsed = parse("[?(@['a'] LTANY [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_lteany_filter_can_be_serialized() {
String filter = filter(where("a").lteany(1)).toString();
String parsed = parse("[?(@['a'] LTEANY [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_gt_filter_can_be_serialized() {
@ -100,6 +128,34 @@ public class FilterParseTest {
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_gtall_filter_can_be_serialized() {
String filter = filter(where("a").gtall(1)).toString();
String parsed = parse("[?(@['a'] GTALL [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_gteall_filter_can_be_serialized() {
String filter = filter(where("a").gteall(1)).toString();
String parsed = parse("[?(@['a'] GTEALL [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_gtany_filter_can_be_serialized() {
String filter = filter(where("a").gtany(1)).toString();
String parsed = parse("[?(@['a'] GTANY [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_gteany_filter_can_be_serialized() {
String filter = filter(where("a").gteany(1)).toString();
String parsed = parse("[?(@['a'] GTEANY [1])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_nin_filter_can_be_serialized() {
String filter = filter(where("a").nin(1)).toString();
@ -125,6 +181,13 @@ public class FilterParseTest {
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_notcontains_filter_can_be_serialized() {
String filter = filter(where("a").notcontains("a")).toString();
String parsed = parse("[?(@['a'] NOTCONTAINS 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_all_filter_can_be_serialized() {
@ -152,6 +215,15 @@ public class FilterParseTest {
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_subsetof_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").subsetof("a")).toString();
String parsed = parse("[?(@['a'] SUBSETOF ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_anyof_filter_can_be_serialized() {
@ -161,6 +233,15 @@ public class FilterParseTest {
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_anyof_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").anyof("a")).toString();
String parsed = parse("[?(@['a'] ANYOF ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_noneof_filter_can_be_serialized() {
@ -170,6 +251,15 @@ public class FilterParseTest {
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_noneof_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").noneof("a")).toString();
String parsed = parse("[?(@['a'] NONEOF ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_exists_filter_can_be_serialized() {
@ -275,4 +365,179 @@ public class FilterParseTest {
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_allmatch_filter_can_be_serialized() {
String filter = filter(where("a").allmatch(Collections.emptyList())).toString();
String parsed = parse("[?(@['a'] ALLMATCH [])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_anymatch_filter_can_be_serialized() {
String filter = filter(where("a").anymatch(Collections.emptyList())).toString();
String parsed = parse("[?(@['a'] ANYMATCH [])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_nonematch_filter_can_be_serialized() {
String filter = filter(where("a").nonematch(Collections.emptyList())).toString();
String parsed = parse("[?(@['a'] NONEMATCH [])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_exactmatch_filter_can_be_serialized() {
String filter = filter(where("a").exactmatch(Collections.emptyList())).toString();
String parsed = parse("[?(@['a'] EXACTMATCH [])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_allmatch_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").allmatch("a")).toString();
String parsed = parse("[?(@['a'] ALLMATCH ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_anymatch_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").anymatch("a")).toString();
String parsed = parse("[?(@['a'] ANYMATCH ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_nonematch_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").nonematch("a")).toString();
String parsed = parse("[?(@['a'] NONEMATCH ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_exactmatch_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").exactmatch("a")).toString();
String parsed = parse("[?(@['a'] EXACTMATCH ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_dateeq_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").dateeq("a")).toString();
String parsed = parse("[?(@['a'] DATEEQ 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_dayeq_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").dayeq("a")).toString();
String parsed = parse("[?(@['a'] DAYEQ 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_dayin_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").dayin("a")).toString();
String parsed = parse("[?(@['a'] DAYIN ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_montheq_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").montheq("a")).toString();
String parsed = parse("[?(@['a'] MONTHEQ 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_monthin_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").monthin("a")).toString();
String parsed = parse("[?(@['a'] MONTHIN ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_yeareq_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").yeareq("a")).toString();
String parsed = parse("[?(@['a'] YEAREQ 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_yearin_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").yearin("a")).toString();
String parsed = parse("[?(@['a'] YEARIN ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_before_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").before("a")).toString();
String parsed = parse("[?(@['a'] BEFORE 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_after_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").after("a")).toString();
String parsed = parse("[?(@['a'] AFTER 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_houreq_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").houreq("a")).toString();
String parsed = parse("[?(@['a'] HOUREQ 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_hourin_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").hourin("a")).toString();
String parsed = parse("[?(@['a'] HOURIN ['a'])]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_timebefore_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").timebefore("a")).toString();
String parsed = parse("[?(@['a'] TIMEBEFORE 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_timeafter_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").timeafter("a")).toString();
String parsed = parse("[?(@['a'] TIMEAFTER 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_windowin_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").windowin("a")).toString();
String parsed = parse("[?(@['a'] WINDOWIN 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_windowout_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").windowout("a")).toString();
String parsed = parse("[?(@['a'] WINDOWOUT 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_windowtimein_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").windowtimein("a")).toString();
String parsed = parse("[?(@['a'] WINDOWTIMEIN 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
@Test
public void a_windowtimeout_objectrange_filter_can_be_serialized() {
String filter = filter(where("a").windowtimeout("a")).toString();
String parsed = parse("[?(@['a'] WINDOWTIMEOUT 'a')]").toString();
assertThat(filter).isEqualTo(parsed);
}
}

Loading…
Cancel
Save