12 changed files with 613 additions and 404 deletions
@ -0,0 +1,268 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.JsonPathException; |
||||
import com.jayway.jsonpath.Predicate; |
||||
|
||||
import java.util.EnumMap; |
||||
|
||||
public class DefaultEvaluatorFactory implements EvaluatorFactory { |
||||
|
||||
private static final EnumMap<RelationalOperator, Evaluator> evaluators |
||||
= new EnumMap<RelationalOperator, Evaluator>(RelationalOperator.class); |
||||
|
||||
static { |
||||
evaluators.put(RelationalOperator.EXISTS, new ExistsEvaluator()); |
||||
evaluators.put(RelationalOperator.NE, new NotEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.TSNE, new TypeSafeNotEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.EQ, new EqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.TSEQ, new TypeSafeEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.LT, new LessThanEvaluator()); |
||||
evaluators.put(RelationalOperator.LTE, new LessThanEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.GT, new GreaterThanEvaluator()); |
||||
evaluators.put(RelationalOperator.GTE, new GreaterThanEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.REGEX, new RegexpEvaluator()); |
||||
evaluators.put(RelationalOperator.SIZE, new SizeEvaluator()); |
||||
evaluators.put(RelationalOperator.EMPTY, new EmptyEvaluator()); |
||||
evaluators.put(RelationalOperator.IN, new InEvaluator()); |
||||
evaluators.put(RelationalOperator.NIN, new NotInEvaluator()); |
||||
evaluators.put(RelationalOperator.ALL, new AllEvaluator()); |
||||
evaluators.put(RelationalOperator.CONTAINS, new ContainsEvaluator()); |
||||
evaluators.put(RelationalOperator.MATCHES, new PredicateMatchEvaluator()); |
||||
evaluators.put(RelationalOperator.TYPE, new TypeEvaluator()); |
||||
} |
||||
|
||||
@Override |
||||
public 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()){ |
||||
throw new JsonPathException("Failed to evaluate exists expression"); |
||||
} |
||||
return left.asBooleanNode().getBoolean() == right.asBooleanNode().getBoolean(); |
||||
} |
||||
} |
||||
|
||||
private static class NotEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return !evaluators.get(RelationalOperator.EQ).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class TypeSafeNotEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return !evaluators.get(RelationalOperator.TSEQ).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class EqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isJsonNode() && right.isJsonNode()){ |
||||
return left.asJsonNode().equals(right.asJsonNode(), ctx); |
||||
} else { |
||||
return left.equals(right); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static class TypeSafeEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(!left.getClass().equals(right.getClass())){ |
||||
return false; |
||||
} |
||||
return evaluators.get(RelationalOperator.EQ).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class TypeEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return right.asClassNode().getClazz() == left.type(ctx); |
||||
} |
||||
} |
||||
|
||||
private static class LessThanEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) < 0; |
||||
} if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) < 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class LessThanEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) <= 0; |
||||
} if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) <= 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class GreaterThanEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) > 0; |
||||
} else if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) > 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class GreaterThanEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) >= 0; |
||||
} else if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) >= 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class SizeEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if (! right.isNumberNode()) { |
||||
return false; |
||||
} |
||||
int expectedSize = right.asNumberNode().getNumber().intValue(); |
||||
|
||||
if(left.isStringNode()){ |
||||
return left.asStringNode().length() == expectedSize; |
||||
} else if(left.isJsonNode()){ |
||||
return left.asJsonNode().length(ctx) == expectedSize; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class EmptyEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isStringNode()){ |
||||
return left.asStringNode().isEmpty() == right.asBooleanNode().getBoolean(); |
||||
} else if(left.isJsonNode()){ |
||||
return left.asJsonNode().isEmpty(ctx) == right.asBooleanNode().getBoolean(); |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class InEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
ValueNode.ValueListNode valueListNode; |
||||
if(right.isJsonNode()){ |
||||
ValueNode vn = right.asJsonNode().asValueListNode(ctx); |
||||
if(vn.isUndefinedNode()){ |
||||
return false; |
||||
} else { |
||||
valueListNode = vn.asValueListNode(); |
||||
} |
||||
} else { |
||||
valueListNode = right.asValueListNode(); |
||||
} |
||||
return valueListNode.contains(left); |
||||
} |
||||
} |
||||
|
||||
private static class NotInEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return !evaluators.get(RelationalOperator.IN).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class AllEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
ValueNode.ValueListNode requiredValues = right.asValueListNode(); |
||||
|
||||
if(left.isJsonNode()){ |
||||
ValueNode valueNode = left.asJsonNode().asValueListNode(ctx); //returns UndefinedNode if conversion is not possible
|
||||
if(valueNode.isValueListNode()){ |
||||
ValueNode.ValueListNode shouldContainAll = valueNode.asValueListNode(); |
||||
for (ValueNode required : requiredValues) { |
||||
if(!shouldContainAll.contains(required)){ |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class ContainsEvaluator 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; |
||||
else { |
||||
boolean res = valueNode.asValueListNode().contains(right); |
||||
return res; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class PredicateMatchEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return right.asPredicateNode().getPredicate().apply(ctx); |
||||
} |
||||
} |
||||
|
||||
private static class RegexpEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(!(left.isPatternNode() ^ right.isPatternNode())){ |
||||
return false; |
||||
} |
||||
|
||||
if (left.isPatternNode()) { |
||||
return matches(left.asPatternNode(), getInput(right)); |
||||
} else { |
||||
return matches(right.asPatternNode(), getInput(left)); |
||||
} |
||||
} |
||||
|
||||
private boolean matches(ValueNode.PatternNode patternNode, String inputToMatch) { |
||||
return patternNode.getCompiledPattern().matcher(inputToMatch).matches(); |
||||
} |
||||
|
||||
private String getInput(ValueNode valueNode) { |
||||
String input = ""; |
||||
|
||||
if (valueNode.isStringNode() || valueNode.isNumberNode()) { |
||||
input = valueNode.asStringNode().getString(); |
||||
} else if (valueNode.isBooleanNode()) { |
||||
input = valueNode.asBooleanNode().toString(); |
||||
} |
||||
|
||||
return input; |
||||
} |
||||
} |
||||
} |
@ -1,267 +1,9 @@
|
||||
// (c) Copyright 2016 Likelihood, Inc.
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.JsonPathException; |
||||
import com.jayway.jsonpath.Predicate; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class EvaluatorFactory { |
||||
|
||||
private static final Map<RelationalOperator, Evaluator> evaluators = new HashMap<RelationalOperator, Evaluator>(); |
||||
|
||||
static { |
||||
evaluators.put(RelationalOperator.EXISTS, new ExistsEvaluator()); |
||||
evaluators.put(RelationalOperator.NE, new NotEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.TSNE, new TypeSafeNotEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.EQ, new EqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.TSEQ, new TypeSafeEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.LT, new LessThanEvaluator()); |
||||
evaluators.put(RelationalOperator.LTE, new LessThanEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.GT, new GreaterThanEvaluator()); |
||||
evaluators.put(RelationalOperator.GTE, new GreaterThanEqualsEvaluator()); |
||||
evaluators.put(RelationalOperator.REGEX, new RegexpEvaluator()); |
||||
evaluators.put(RelationalOperator.SIZE, new SizeEvaluator()); |
||||
evaluators.put(RelationalOperator.EMPTY, new EmptyEvaluator()); |
||||
evaluators.put(RelationalOperator.IN, new InEvaluator()); |
||||
evaluators.put(RelationalOperator.NIN, new NotInEvaluator()); |
||||
evaluators.put(RelationalOperator.ALL, new AllEvaluator()); |
||||
evaluators.put(RelationalOperator.CONTAINS, new ContainsEvaluator()); |
||||
evaluators.put(RelationalOperator.MATCHES, new PredicateMatchEvaluator()); |
||||
evaluators.put(RelationalOperator.TYPE, new TypeEvaluator()); |
||||
} |
||||
|
||||
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()){ |
||||
throw new JsonPathException("Failed to evaluate exists expression"); |
||||
} |
||||
return left.asBooleanNode().getBoolean() == right.asBooleanNode().getBoolean(); |
||||
} |
||||
} |
||||
|
||||
private static class NotEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return !evaluators.get(RelationalOperator.EQ).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class TypeSafeNotEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return !evaluators.get(RelationalOperator.TSEQ).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class EqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isJsonNode() && right.isJsonNode()){ |
||||
return left.asJsonNode().equals(right.asJsonNode(), ctx); |
||||
} else { |
||||
return left.equals(right); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private static class TypeSafeEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(!left.getClass().equals(right.getClass())){ |
||||
return false; |
||||
} |
||||
return evaluators.get(RelationalOperator.EQ).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class TypeEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return right.asClassNode().getClazz() == left.type(ctx); |
||||
} |
||||
} |
||||
|
||||
private static class LessThanEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) < 0; |
||||
} if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) < 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class LessThanEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) <= 0; |
||||
} if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) <= 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class GreaterThanEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) > 0; |
||||
} else if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) > 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class GreaterThanEqualsEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isNumberNode() && right.isNumberNode()){ |
||||
return left.asNumberNode().getNumber().compareTo(right.asNumberNode().getNumber()) >= 0; |
||||
} else if(left.isStringNode() && right.isStringNode()){ |
||||
return left.asStringNode().getString().compareTo(right.asStringNode().getString()) >= 0; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class SizeEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if (! right.isNumberNode()) { |
||||
return false; |
||||
} |
||||
int expectedSize = right.asNumberNode().getNumber().intValue(); |
||||
|
||||
if(left.isStringNode()){ |
||||
return left.asStringNode().length() == expectedSize; |
||||
} else if(left.isJsonNode()){ |
||||
return left.asJsonNode().length(ctx) == expectedSize; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class EmptyEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isStringNode()){ |
||||
return left.asStringNode().isEmpty() == right.asBooleanNode().getBoolean(); |
||||
} else if(left.isJsonNode()){ |
||||
return left.asJsonNode().isEmpty(ctx) == right.asBooleanNode().getBoolean(); |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class InEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
ValueNode.ValueListNode valueListNode; |
||||
if(right.isJsonNode()){ |
||||
ValueNode vn = right.asJsonNode().asValueListNode(ctx); |
||||
if(vn.isUndefinedNode()){ |
||||
return false; |
||||
} else { |
||||
valueListNode = vn.asValueListNode(); |
||||
} |
||||
} else { |
||||
valueListNode = right.asValueListNode(); |
||||
} |
||||
return valueListNode.contains(left); |
||||
} |
||||
} |
||||
|
||||
private static class NotInEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return !evaluators.get(RelationalOperator.IN).evaluate(left, right, ctx); |
||||
} |
||||
} |
||||
|
||||
private static class AllEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
ValueNode.ValueListNode requiredValues = right.asValueListNode(); |
||||
|
||||
if(left.isJsonNode()){ |
||||
ValueNode valueNode = left.asJsonNode().asValueListNode(ctx); //returns UndefinedNode if conversion is not possible
|
||||
if(valueNode.isValueListNode()){ |
||||
ValueNode.ValueListNode shouldContainAll = valueNode.asValueListNode(); |
||||
for (ValueNode required : requiredValues) { |
||||
if(!shouldContainAll.contains(required)){ |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class ContainsEvaluator 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; |
||||
else { |
||||
boolean res = valueNode.asValueListNode().contains(right); |
||||
return res; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class PredicateMatchEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
return right.asPredicateNode().getPredicate().apply(ctx); |
||||
} |
||||
} |
||||
|
||||
private static class RegexpEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(!(left.isPatternNode() ^ right.isPatternNode())){ |
||||
return false; |
||||
} |
||||
|
||||
if (left.isPatternNode()) { |
||||
return matches(left.asPatternNode(), getInput(right)); |
||||
} else { |
||||
return matches(right.asPatternNode(), getInput(left)); |
||||
} |
||||
} |
||||
|
||||
private boolean matches(ValueNode.PatternNode patternNode, String inputToMatch) { |
||||
return patternNode.getCompiledPattern().matcher(inputToMatch).matches(); |
||||
} |
||||
|
||||
private String getInput(ValueNode valueNode) { |
||||
String input = ""; |
||||
|
||||
if (valueNode.isStringNode() || valueNode.isNumberNode()) { |
||||
input = valueNode.asStringNode().getString(); |
||||
} else if (valueNode.isBooleanNode()) { |
||||
input = valueNode.asBooleanNode().toString(); |
||||
} |
||||
|
||||
return input; |
||||
} |
||||
} |
||||
/** |
||||
* Interface for creating evaluators. |
||||
*/ |
||||
public interface EvaluatorFactory { |
||||
Evaluator createEvaluator(RelationalOperator operator); |
||||
} |
||||
|
@ -0,0 +1,60 @@
|
||||
// (c) Copyright 2016 Likelihood, Inc.
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import java.util.EnumMap; |
||||
|
||||
import com.jayway.jsonpath.Predicate.PredicateContext; |
||||
import com.jayway.jsonpath.internal.filter.ValueNode.NumberNode; |
||||
|
||||
/** |
||||
* Factory that supports implicit numeric conversions for evaluators. |
||||
*/ |
||||
public class ImplicitNumericConversionEvaluatorFactory implements EvaluatorFactory { |
||||
|
||||
private final EnumMap<RelationalOperator, Evaluator> |
||||
evaluators = new EnumMap<RelationalOperator, Evaluator>(RelationalOperator.class); |
||||
|
||||
public ImplicitNumericConversionEvaluatorFactory(EvaluatorFactory delegateFactory) { |
||||
// for each operator, wrap just the ones that allow implicit numeric conversion.
|
||||
for (RelationalOperator op : RelationalOperator.values()) { |
||||
Evaluator delegateEvaluator = delegateFactory.createEvaluator(op); |
||||
if (delegateEvaluator != null) { |
||||
evaluators.put( |
||||
op, |
||||
op.allowImplicitNumericConversion() |
||||
? new Wrapper(delegateEvaluator) |
||||
: delegateEvaluator); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Evaluator createEvaluator(RelationalOperator operator) { |
||||
return evaluators.get(operator); |
||||
} |
||||
|
||||
private static class Wrapper implements Evaluator { |
||||
Evaluator wrapped; |
||||
|
||||
Wrapper(Evaluator wrapped) { |
||||
this.wrapped = wrapped; |
||||
} |
||||
|
||||
@Override |
||||
public boolean evaluate( |
||||
ValueNode left, ValueNode right, PredicateContext ctx) { |
||||
final boolean eval = wrapped.evaluate(left, right, ctx); |
||||
if (!eval) { |
||||
if (left.isNumberNode() && right.isStringNode()) { |
||||
final ValueNode converted = right.asNumberNode(); |
||||
return (converted != NumberNode.NAN) && wrapped.evaluate(left, converted, ctx); |
||||
} |
||||
if (left.isStringNode() && right.isNumberNode()) { |
||||
final ValueNode converted = left.asNumberNode(); |
||||
return (converted != NumberNode.NAN) && wrapped.evaluate(converted, right, ctx); |
||||
} |
||||
} |
||||
return eval; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue