Kalle Stenflo
9 years ago
26 changed files with 2210 additions and 1208 deletions
File diff suppressed because it is too large
Load Diff
@ -1,109 +0,0 @@
|
||||
/* |
||||
* Copyright 2011 the original author or authors. |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.jayway.jsonpath.internal; |
||||
|
||||
import java.util.Deque; |
||||
import java.util.LinkedList; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.locks.ReentrantLock; |
||||
|
||||
public class Cache { |
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(); |
||||
|
||||
private final Map<String, Path> map = new ConcurrentHashMap<String, Path>(); |
||||
private final Deque<String> queue = new LinkedList<String>(); |
||||
private final int limit; |
||||
|
||||
public Cache(int limit) { |
||||
this.limit = limit; |
||||
} |
||||
|
||||
public void put(String key, Path value) { |
||||
Path oldValue = map.put(key, value); |
||||
if (oldValue != null) { |
||||
removeThenAddKey(key); |
||||
} else { |
||||
addKey(key); |
||||
} |
||||
if (map.size() > limit) { |
||||
map.remove(removeLast()); |
||||
} |
||||
} |
||||
|
||||
public Path get(String key) { |
||||
if(map.containsKey(key)){ |
||||
removeThenAddKey(key); |
||||
} |
||||
return map.get(key); |
||||
} |
||||
|
||||
private void addKey(String key) { |
||||
lock.lock(); |
||||
try { |
||||
queue.addFirst(key); |
||||
} finally { |
||||
lock.unlock(); |
||||
} |
||||
} |
||||
|
||||
private String removeLast() { |
||||
lock.lock(); |
||||
try { |
||||
final String removedKey = queue.removeLast(); |
||||
return removedKey; |
||||
} finally { |
||||
lock.unlock(); |
||||
} |
||||
} |
||||
|
||||
private void removeThenAddKey(String key) { |
||||
lock.lock(); |
||||
try { |
||||
queue.removeFirstOccurrence(key); |
||||
queue.addFirst(key); |
||||
} finally { |
||||
lock.unlock(); |
||||
} |
||||
|
||||
} |
||||
|
||||
private void removeFirstOccurrence(String key) { |
||||
lock.lock(); |
||||
try { |
||||
queue.removeFirstOccurrence(key); |
||||
} finally { |
||||
lock.unlock(); |
||||
} |
||||
} |
||||
|
||||
public Path getSilent(String key) { |
||||
return map.get(key); |
||||
} |
||||
|
||||
public void remove(String key) { |
||||
removeFirstOccurrence(key); |
||||
map.remove(key); |
||||
} |
||||
|
||||
public int size() { |
||||
return map.size(); |
||||
} |
||||
|
||||
public String toString() { |
||||
return map.toString(); |
||||
} |
||||
} |
@ -0,0 +1,280 @@
|
||||
package com.jayway.jsonpath.internal; |
||||
|
||||
import com.jayway.jsonpath.InvalidPathException; |
||||
|
||||
public class CharacterIndex { |
||||
|
||||
private static final char OPEN_BRACKET = '('; |
||||
private static final char CLOSE_BRACKET = ')'; |
||||
private static final char CLOSE_SQUARE_BRACKET = ']'; |
||||
private static final char SPACE = ' '; |
||||
private static final char ESCAPE = '\\'; |
||||
private static final char TICK = '\''; |
||||
private static final char MINUS = '-'; |
||||
private static final char PERIOD = '.'; |
||||
private static final char REGEX = '/'; |
||||
|
||||
private final CharSequence charSequence; |
||||
private int position; |
||||
|
||||
public CharacterIndex(CharSequence charSequence) { |
||||
this.charSequence = charSequence; |
||||
this.position = 0; |
||||
} |
||||
|
||||
public int length() { |
||||
return charSequence.length(); |
||||
} |
||||
|
||||
public char charAt(int idx) { |
||||
return charSequence.charAt(idx); |
||||
} |
||||
|
||||
public char currentChar() { |
||||
return charSequence.charAt(position); |
||||
} |
||||
|
||||
public boolean currentCharIs(char c) { |
||||
return (charSequence.charAt(position) == c); |
||||
} |
||||
|
||||
public boolean nextCharIs(char c) { |
||||
return inBounds(position + 1) && (charSequence.charAt(position + 1) == c); |
||||
} |
||||
|
||||
public int incrementPosition(int charCount) { |
||||
return setPosition(position + charCount); |
||||
} |
||||
|
||||
public int setPosition(int newPosition) { |
||||
//position = min(newPosition, charSequence.length() - 1);
|
||||
position = newPosition; |
||||
return position; |
||||
} |
||||
|
||||
public int position(){ |
||||
return position; |
||||
} |
||||
|
||||
public int indexOfClosingSquareBracket(int startPosition) { |
||||
int readPosition = startPosition; |
||||
while (inBounds(readPosition)) { |
||||
if(charAt(readPosition) == CLOSE_SQUARE_BRACKET){ |
||||
return readPosition; |
||||
} |
||||
readPosition++; |
||||
} |
||||
return -1; |
||||
} |
||||
public int indexOfMatchingCloseChar(int startPosition, char openChar, char closeChar, boolean skipStrings, boolean skipRegex) { |
||||
if(charAt(startPosition) != openChar){ |
||||
throw new InvalidPathException("Expected " + openChar + " but found " + charAt(startPosition)); |
||||
} |
||||
|
||||
int opened = 1; |
||||
int readPosition = startPosition + 1; |
||||
while (inBounds(readPosition)) { |
||||
if (skipStrings) { |
||||
if (charAt(readPosition) == TICK) { |
||||
boolean escaped = false; |
||||
while (inBounds(readPosition)) { |
||||
readPosition++; |
||||
if (escaped) { |
||||
escaped = false; |
||||
continue; |
||||
} |
||||
if (charAt(readPosition) == ESCAPE) { |
||||
escaped = true; |
||||
continue; |
||||
} |
||||
if (charAt(readPosition) == TICK) { |
||||
readPosition++; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (skipRegex) { |
||||
if (charAt(readPosition) == REGEX) { |
||||
while (inBounds(readPosition)) { |
||||
readPosition++; |
||||
if (charAt(readPosition) == REGEX) { |
||||
readPosition++; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
if (charAt(readPosition) == openChar) { |
||||
opened++; |
||||
} |
||||
if (charAt(readPosition) == closeChar) { |
||||
opened--; |
||||
if (opened == 0) { |
||||
return readPosition; |
||||
} |
||||
} |
||||
readPosition++; |
||||
} |
||||
return -1; |
||||
} |
||||
public int indexOfClosingBracket(int startPosition, boolean skipStrings, boolean skipRegex) { |
||||
return indexOfMatchingCloseChar(startPosition, OPEN_BRACKET, CLOSE_BRACKET, skipStrings, skipRegex); |
||||
} |
||||
|
||||
public int indexOfNextSignificantChar(char c) { |
||||
return indexOfNextSignificantChar(position, c); |
||||
} |
||||
|
||||
public int indexOfNextSignificantChar(int startPosition, char c) { |
||||
int readPosition = startPosition + 1; |
||||
while (!isOutOfBounds(readPosition) && charAt(readPosition) == SPACE) { |
||||
readPosition++; |
||||
} |
||||
if (charAt(readPosition) == c) { |
||||
return readPosition; |
||||
} else { |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
public int nextIndexOf(char c) { |
||||
return nextIndexOf(position + 1, c); |
||||
} |
||||
|
||||
public int nextIndexOf(int startPosition, char c) { |
||||
int readPosition = startPosition; |
||||
while (!isOutOfBounds(readPosition)) { |
||||
if (charAt(readPosition) == c) { |
||||
return readPosition; |
||||
} |
||||
readPosition++; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
public int nextIndexOfUnescaped(char c) { |
||||
return nextIndexOfUnescaped(position + 1, c); |
||||
} |
||||
|
||||
public int nextIndexOfUnescaped(int startPosition, char c) { |
||||
int readPosition = startPosition; |
||||
char prev1; |
||||
char prev2; |
||||
while (!isOutOfBounds(readPosition)) { |
||||
prev1 = charAtOr(readPosition - 1, ' '); |
||||
prev2 = charAtOr(readPosition - 2, ' '); |
||||
boolean ignore = (prev1 == '\\' && prev2 == '\\'); |
||||
boolean escaped = (prev1 == '\\' && !ignore); |
||||
|
||||
if (charAt(readPosition) == c && !escaped) { |
||||
return readPosition; |
||||
} |
||||
readPosition++; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
public char charAtOr(int postition, char defaultChar){ |
||||
if(!inBounds(postition)) return defaultChar; |
||||
else return charAt(postition); |
||||
} |
||||
|
||||
public boolean nextSignificantCharIs(int startPosition, char c) { |
||||
int readPosition = startPosition + 1; |
||||
while (!isOutOfBounds(readPosition) && charAt(readPosition) == SPACE) { |
||||
readPosition++; |
||||
} |
||||
return !isOutOfBounds(readPosition) && charAt(readPosition) == c; |
||||
} |
||||
|
||||
public boolean nextSignificantCharIs(char c) { |
||||
return nextSignificantCharIs(position, c); |
||||
} |
||||
|
||||
public char nextSignificantChar() { |
||||
return nextSignificantChar(position); |
||||
} |
||||
|
||||
public char nextSignificantChar(int startPosition) { |
||||
int readPosition = startPosition + 1; |
||||
while (!isOutOfBounds(readPosition) && charAt(readPosition) == SPACE) { |
||||
readPosition++; |
||||
} |
||||
if (!isOutOfBounds(readPosition)) { |
||||
return charAt(readPosition); |
||||
} else { |
||||
return ' '; |
||||
} |
||||
} |
||||
|
||||
public int indexOfPreviousSignificantChar(int startPosition){ |
||||
int readPosition = startPosition - 1; |
||||
while (!isOutOfBounds(readPosition) && charAt(readPosition) == SPACE) { |
||||
readPosition--; |
||||
} |
||||
if (!isOutOfBounds(readPosition)) { |
||||
return readPosition; |
||||
} else { |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
public int indexOfPreviousSignificantChar(){ |
||||
return indexOfPreviousSignificantChar(position); |
||||
} |
||||
|
||||
public char previousSignificantChar(int startPosition) { |
||||
int previousSignificantCharIndex = indexOfPreviousSignificantChar(startPosition); |
||||
if(previousSignificantCharIndex == -1) return ' '; |
||||
else return charAt(previousSignificantCharIndex); |
||||
} |
||||
|
||||
public char previousSignificantChar() { |
||||
return previousSignificantChar(position); |
||||
} |
||||
|
||||
public boolean currentIsTail() { |
||||
return isOutOfBounds(position + 1); |
||||
} |
||||
|
||||
public boolean hasMoreCharacters() { |
||||
return inBounds(position + 1); |
||||
} |
||||
|
||||
public boolean inBounds(int idx) { |
||||
return (idx >= 0) && (idx < charSequence.length()); |
||||
} |
||||
public boolean inBounds() { |
||||
return inBounds(position); |
||||
} |
||||
|
||||
public boolean isOutOfBounds(int idx) { |
||||
return !inBounds(idx); |
||||
} |
||||
|
||||
public CharSequence subSequence(int start, int end) { |
||||
return charSequence.subSequence(start, end); |
||||
} |
||||
|
||||
public CharSequence charSequence() { |
||||
return charSequence; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return charSequence.toString(); |
||||
} |
||||
|
||||
public boolean isNumberCharacter(int readPosition) { |
||||
char c = charAt(readPosition); |
||||
return Character.isDigit(c) || c == MINUS || c == PERIOD; |
||||
} |
||||
|
||||
public CharacterIndex skipBlanks() { |
||||
while (inBounds() && currentChar() == SPACE){ |
||||
incrementPosition(1); |
||||
} |
||||
return this; |
||||
} |
||||
} |
@ -0,0 +1,7 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.Predicate; |
||||
|
||||
public interface Evaluator { |
||||
boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx); |
||||
} |
@ -0,0 +1,220 @@
|
||||
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.EQ, new EqualsEvaluator()); |
||||
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.NOT_EMPTY, new NotEmptyEvaluator()); |
||||
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 !left.equals(right); |
||||
} |
||||
} |
||||
|
||||
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 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) { |
||||
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 NotEmptyEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
if(left.isStringNode()){ |
||||
return !left.asStringNode().isEmpty(); |
||||
} else if(left.isJsonNode()){ |
||||
return !left.asJsonNode().isEmpty(ctx); |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
private static class InEvaluator implements Evaluator { |
||||
@Override |
||||
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { |
||||
ValueNode.ValueListNode 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.isStringNode() ^ right.isStringNode())){ |
||||
return false; |
||||
} |
||||
ValueNode.PatternNode patternNode = left.isPatternNode() ? left.asPatternNode() : right.asPatternNode(); |
||||
ValueNode.StringNode stringNode = left.isStringNode() ? left.asStringNode() : right.asStringNode(); |
||||
|
||||
return patternNode.getCompiledPattern().matcher(stringNode.getString()).matches(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.Predicate; |
||||
|
||||
public abstract class ExpressionNode implements Predicate { |
||||
|
||||
public static ExpressionNode createExpressionNode(ExpressionNode right, LogicalOperator operator, ExpressionNode left){ |
||||
if(operator == LogicalOperator.AND){ |
||||
if((left instanceof LogicalExpressionNode) && ((LogicalExpressionNode)left).getOperator() == LogicalOperator.AND ){ |
||||
LogicalExpressionNode len = (LogicalExpressionNode) left; |
||||
return len.append(right); |
||||
} else { |
||||
return LogicalExpressionNode.createLogicalAnd(left, right); |
||||
} |
||||
} else { |
||||
if((left instanceof LogicalExpressionNode) && ((LogicalExpressionNode)left).getOperator() == LogicalOperator.OR ){ |
||||
LogicalExpressionNode len = (LogicalExpressionNode) left; |
||||
return len.append(right); |
||||
} else { |
||||
return LogicalExpressionNode.createLogicalOr(left, right); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,343 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.InvalidPathException; |
||||
import com.jayway.jsonpath.Predicate; |
||||
import com.jayway.jsonpath.internal.CharacterIndex; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.util.Stack; |
||||
|
||||
public class FilterCompiler { |
||||
private static final Logger logger = LoggerFactory.getLogger(FilterCompiler.class); |
||||
|
||||
private static final char DOC_CONTEXT = '$'; |
||||
private static final char EVAL_CONTEXT = '@'; |
||||
private static final char OPEN_SQUARE_BRACKET = '['; |
||||
private static final char CLOSE_SQUARE_BRACKET = ']'; |
||||
private static final char OPEN_BRACKET = '('; |
||||
private static final char CLOSE_BRACKET = ')'; |
||||
private static final char WILDCARD = '*'; |
||||
private static final char PERIOD = '.'; |
||||
private static final char SPACE = ' '; |
||||
private static final char QUESTIONMARK = '?'; |
||||
private static final char COMMA = ','; |
||||
private static final char SPLIT = ':'; |
||||
private static final char MINUS = '-'; |
||||
private static final char TICK = '\''; |
||||
private static final char FUNCTION = '%'; |
||||
private static final char OPERATOR_PIPE = '¦'; |
||||
private static final char LT = '<'; |
||||
private static final char GT = '>'; |
||||
private static final char EQ = '='; |
||||
private static final char TILDE = '~'; |
||||
private static final char TRUE = 't'; |
||||
private static final char FALSE = 'f'; |
||||
private static final char NULL = 'n'; |
||||
private static final char AND = '&'; |
||||
private static final char OR = '|'; |
||||
private static final char OBJECT_OPEN = '{'; |
||||
private static final char OBJECT_CLOSE = '}'; |
||||
private static final char ARRAY_OPEN = '['; |
||||
private static final char ARRAY_CLOSE = ']'; |
||||
private static final char BANG = '!'; |
||||
private static final char PATTERN = '/'; |
||||
|
||||
private CharacterIndex filter; |
||||
|
||||
public static Predicate compile(String filterString) { |
||||
FilterCompiler compiler = new FilterCompiler(filterString); |
||||
return compiler.compile(); |
||||
} |
||||
|
||||
private FilterCompiler(String filterString) { |
||||
filterString = filterString.trim(); |
||||
if (!filterString.startsWith("[") || !filterString.endsWith("]")) { |
||||
throw new InvalidPathException("Filter must start with '[' and end with ']'. " + filterString); |
||||
} |
||||
filterString = filterString.substring(1, filterString.length() - 1).trim(); |
||||
if (!filterString.startsWith("?")) { |
||||
throw new InvalidPathException("Filter must start with '[?' and end with ']'. " + filterString); |
||||
} |
||||
filterString = filterString.substring(1).trim(); |
||||
if (!filterString.startsWith("(") || !filterString.endsWith(")")) { |
||||
throw new InvalidPathException("Filter must start with '[?(' and end with ')]'. " + filterString); |
||||
} |
||||
// filterString = filterString.substring(1, filterString.length() - 1).trim();
|
||||
|
||||
filter = new CharacterIndex(filterString); |
||||
} |
||||
|
||||
public Predicate compile() { |
||||
|
||||
Stack<LogicalOperator> opsStack = new Stack<LogicalOperator>(); |
||||
Stack<ExpressionNode> expStack = new Stack<ExpressionNode>(); |
||||
|
||||
int unbalancedBrackets = 0; |
||||
|
||||
while (filter.skipBlanks().inBounds()) { |
||||
int pos = filter.position(); |
||||
|
||||
switch (filter.currentChar()) { |
||||
case OPEN_BRACKET: |
||||
unbalancedBrackets++; |
||||
filter.incrementPosition(1); |
||||
break; |
||||
case CLOSE_BRACKET: |
||||
unbalancedBrackets--; |
||||
filter.incrementPosition(1); |
||||
while(!opsStack.isEmpty()){ |
||||
//expStack.push(opsStack.pop().createExpressionNode(expStack.pop(), expStack.pop()));
|
||||
expStack.push(ExpressionNode.createExpressionNode(expStack.pop(), opsStack.pop(), expStack.pop())); |
||||
} |
||||
break; |
||||
case BANG: |
||||
filter.incrementPosition(1); |
||||
break; |
||||
case OR: |
||||
case AND: |
||||
LogicalOperator operatorNode = readLogicalOperator(); |
||||
opsStack.push(operatorNode); |
||||
break; |
||||
default: |
||||
RelationalExpressionNode relationalExpressionNode = readExpression(); |
||||
expStack.push(relationalExpressionNode); |
||||
break; |
||||
} |
||||
if(pos >= filter.position()){ |
||||
throw new InvalidPathException("Failed to parse filter " + filter.toString()); |
||||
} |
||||
} |
||||
if(unbalancedBrackets > 0){ |
||||
throw new InvalidPathException("Failed to parse filter. Brackets are not balanced. " + filter.toString()); |
||||
} |
||||
|
||||
Predicate predicate = expStack.pop(); |
||||
logger.trace("--------> {}", predicate.toString()); |
||||
|
||||
return predicate; |
||||
} |
||||
|
||||
private ValueNode readValueNode() { |
||||
switch (filter.skipBlanks().currentChar()) { |
||||
case DOC_CONTEXT : return readPath(); |
||||
case EVAL_CONTEXT : return readPath(); |
||||
default : return readLiteral(); |
||||
} |
||||
} |
||||
|
||||
private ValueNode readLiteral(){ |
||||
switch (filter.skipBlanks().currentChar()){ |
||||
case TICK: return readStringLiteral(); |
||||
case TRUE: return readBooleanLiteral(); |
||||
case FALSE: return readBooleanLiteral(); |
||||
case MINUS: return readNumberLiteral(); |
||||
case NULL: return readNullLiteral(); |
||||
case OBJECT_OPEN: return readJsonLiteral(); |
||||
case ARRAY_OPEN: return readJsonLiteral(); |
||||
case PATTERN: return readPattern(); |
||||
default: return readNumberLiteral(); |
||||
} |
||||
} |
||||
|
||||
private RelationalExpressionNode readExpression() { |
||||
ValueNode left = readValueNode(); |
||||
if (left.isPathNode()) { |
||||
final PathNode pathNode = left.asPathNode(); |
||||
if (pathNode.isExistsCheck()) { |
||||
|
||||
return new RelationalExpressionNode(pathNode, RelationalOperator.fromString("¦EXISTS¦"), pathNode.shouldExists() ? ValueNode.TRUE : ValueNode.FALSE); |
||||
} |
||||
} |
||||
RelationalOperator operator = readRelationalOperator(); |
||||
ValueNode right = ValueNode.TRUE; |
||||
if(operator != RelationalOperator.NOT_EMPTY) { |
||||
right = readValueNode(); |
||||
} |
||||
|
||||
return new RelationalExpressionNode(left, operator, right); |
||||
} |
||||
|
||||
private LogicalOperator readLogicalOperator(){ |
||||
int begin = filter.skipBlanks().position(); |
||||
int end = begin+1; |
||||
|
||||
if(!filter.inBounds(end)){ |
||||
throw new InvalidPathException("Expected boolean literal"); |
||||
} |
||||
CharSequence logicalOperator = filter.subSequence(begin, end+1); |
||||
if(!logicalOperator.equals("||") && !logicalOperator.equals("&&")){ |
||||
throw new InvalidPathException("Expected logical operator"); |
||||
} |
||||
filter.incrementPosition(logicalOperator.length()); |
||||
logger.trace("LogicalOperator from {} to {} -> [{}]", begin, end, logicalOperator); |
||||
|
||||
return LogicalOperator.fromString(logicalOperator.toString()); |
||||
} |
||||
|
||||
private RelationalOperator readRelationalOperator() { |
||||
int begin = filter.skipBlanks().position(); |
||||
|
||||
if (filter.currentChar() == OPERATOR_PIPE) { |
||||
int closingOperatorIndex = filter.nextIndexOf(OPERATOR_PIPE); |
||||
if (closingOperatorIndex == -1) { |
||||
throw new InvalidPathException("Operator not closed. Expected " + OPERATOR_PIPE + " in " + filter); |
||||
} else { |
||||
filter.setPosition(closingOperatorIndex + 1); |
||||
} |
||||
} else { |
||||
while (filter.inBounds() && isRelationalOperatorChar(filter.currentChar())) { |
||||
filter.incrementPosition(1); |
||||
} |
||||
} |
||||
CharSequence operator = filter.subSequence(begin, filter.position()); |
||||
logger.trace("Operator from {} to {} -> [{}]", begin, filter.position()-1, operator); |
||||
return RelationalOperator.fromString(operator.toString()); |
||||
} |
||||
|
||||
private ValueNode.NullNode readNullLiteral() { |
||||
int begin = filter.position(); |
||||
if(filter.currentChar() == 'n' && filter.inBounds(filter.position() + 3)){ |
||||
CharSequence nullValue = filter.subSequence(filter.position(), filter.position() + 4); |
||||
if("null".endsWith(nullValue.toString())){ |
||||
logger.trace("NullLiteral from {} to {} -> [{}]", begin, filter.position()+3, nullValue); |
||||
filter.incrementPosition(nullValue.length()); |
||||
return ValueNode.createNullNode(); |
||||
} |
||||
} |
||||
throw new InvalidPathException("Expected <null> value"); |
||||
} |
||||
|
||||
private ValueNode.JsonNode readJsonLiteral(){ |
||||
int begin = filter.position(); |
||||
|
||||
char openChar = filter.currentChar(); |
||||
|
||||
assert openChar == ARRAY_OPEN || openChar == OBJECT_OPEN; |
||||
|
||||
char closeChar = openChar == ARRAY_OPEN ? ARRAY_CLOSE : OBJECT_CLOSE; |
||||
|
||||
int closingIndex = filter.indexOfMatchingCloseChar(filter.position(), openChar, closeChar, true, false); |
||||
if (closingIndex == -1) { |
||||
throw new InvalidPathException("String not closed. Expected " + TICK + " in " + filter); |
||||
} else { |
||||
filter.setPosition(closingIndex + 1); |
||||
} |
||||
CharSequence json = filter.subSequence(begin, filter.position()); |
||||
logger.trace("JsonLiteral from {} to {} -> [{}]", begin, filter.position(), json); |
||||
return ValueNode.createJsonNode(json); |
||||
|
||||
} |
||||
|
||||
private ValueNode.PatternNode readPattern() { |
||||
int begin = filter.position(); |
||||
int closingIndex = filter.nextIndexOfUnescaped(PATTERN); |
||||
if (closingIndex == -1) { |
||||
throw new InvalidPathException("Pattern not closed. Expected " + PATTERN + " in " + filter); |
||||
} else { |
||||
if(filter.inBounds(closingIndex+1) && filter.charAt(closingIndex+1) == 'i'){ |
||||
closingIndex++; |
||||
} |
||||
filter.setPosition(closingIndex + 1); |
||||
} |
||||
CharSequence pattern = filter.subSequence(begin, filter.position()); |
||||
logger.trace("PatternNode from {} to {} -> [{}]", begin, filter.position(), pattern); |
||||
return ValueNode.createPatternNode(pattern); |
||||
} |
||||
|
||||
private ValueNode.StringNode readStringLiteral() { |
||||
int begin = filter.position(); |
||||
|
||||
int closingTickIndex = filter.nextIndexOfUnescaped(TICK); |
||||
if (closingTickIndex == -1) { |
||||
throw new InvalidPathException("String not closed. Expected " + TICK + " in " + filter); |
||||
} else { |
||||
filter.setPosition(closingTickIndex + 1); |
||||
} |
||||
CharSequence stringLiteral = filter.subSequence(begin, filter.position()); |
||||
logger.trace("StringLiteral from {} to {} -> [{}]", begin, filter.position(), stringLiteral); |
||||
return ValueNode.createStringNode(stringLiteral, true); |
||||
} |
||||
|
||||
private ValueNode.NumberNode readNumberLiteral() { |
||||
int begin = filter.position(); |
||||
|
||||
while (filter.inBounds() && filter.isNumberCharacter(filter.position())) { |
||||
filter.incrementPosition(1); |
||||
} |
||||
CharSequence numberLiteral = filter.subSequence(begin, filter.position()); |
||||
logger.trace("NumberLiteral from {} to {} -> [{}]", begin, filter.position(), numberLiteral); |
||||
return ValueNode.createNumberNode(numberLiteral); |
||||
} |
||||
|
||||
private ValueNode.BooleanNode readBooleanLiteral() { |
||||
int begin = filter.position(); |
||||
int end = filter.currentChar() == 't' ? filter.position() + 3 : filter.position() + 4; |
||||
|
||||
if(!filter.inBounds(end)){ |
||||
throw new InvalidPathException("Expected boolean literal"); |
||||
} |
||||
CharSequence boolValue = filter.subSequence(begin, end+1); |
||||
if(!boolValue.equals("true") && !boolValue.equals("false")){ |
||||
throw new InvalidPathException("Expected boolean literal"); |
||||
} |
||||
filter.incrementPosition(boolValue.length()); |
||||
logger.trace("BooleanLiteral from {} to {} -> [{}]", begin, end, boolValue); |
||||
|
||||
return ValueNode.createBooleanNode(boolValue); |
||||
} |
||||
|
||||
private PathNode readPath() { |
||||
char previousSignificantChar = filter.previousSignificantChar(); |
||||
boolean operatorOnLeft = isRelationalOperatorChar(previousSignificantChar) && previousSignificantChar != BANG; |
||||
int begin = filter.position(); |
||||
|
||||
filter.incrementPosition(1); //skip $ and @
|
||||
while (filter.inBounds()) { |
||||
if (filter.currentChar() == OPEN_SQUARE_BRACKET) { |
||||
int closingSquareBracketIndex = filter.indexOfClosingSquareBracket(filter.position()); |
||||
if (closingSquareBracketIndex == -1) { |
||||
throw new InvalidPathException("Square brackets does not match in filter " + filter); |
||||
} else { |
||||
filter.setPosition(closingSquareBracketIndex + 1); |
||||
} |
||||
} |
||||
boolean closingLogicalBracket = (filter.currentChar() == CLOSE_BRACKET && !currentCharIsClosingFunctionBracket(begin)); |
||||
if (!filter.inBounds() || isRelationalOperatorChar(filter.currentChar()) || filter.currentChar() == SPACE || closingLogicalBracket) { |
||||
break; |
||||
} else { |
||||
filter.incrementPosition(1); |
||||
} |
||||
} |
||||
boolean operatorOnRight = isRelationalOperatorChar(filter.currentChar()) || isRelationalOperatorChar(filter.nextSignificantChar()); |
||||
boolean existsCheck = !operatorOnLeft && !operatorOnRight; |
||||
boolean shouldExists = true; |
||||
if(existsCheck){ |
||||
shouldExists = !(previousSignificantChar == BANG); |
||||
} |
||||
CharSequence path = filter.subSequence(begin, filter.position()); |
||||
return new PathNode(path, existsCheck, shouldExists); |
||||
} |
||||
|
||||
private boolean currentCharIsClosingFunctionBracket(int lowerBound){ |
||||
if(filter.currentChar() != CLOSE_BRACKET){ |
||||
return false; |
||||
} |
||||
int idx = filter.indexOfPreviousSignificantChar(); |
||||
if(idx == -1 || filter.charAt(idx) != OPEN_BRACKET){ |
||||
return false; |
||||
} |
||||
idx--; |
||||
while(filter.inBounds(idx) && idx > lowerBound){ |
||||
if(filter.charAt(idx) == FUNCTION){ |
||||
return true; |
||||
} |
||||
idx--; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private boolean isRelationalOperatorChar(char c) { |
||||
return c == OPERATOR_PIPE || c == LT || c == GT || c == EQ || c == TILDE || c == BANG; |
||||
} |
||||
} |
@ -0,0 +1,11 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.Predicate; |
||||
|
||||
public class FunctionNode extends ValueNode { |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Void.class; |
||||
} |
||||
} |
@ -0,0 +1,67 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.internal.Utils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
public class LogicalExpressionNode extends ExpressionNode { |
||||
protected List<ExpressionNode> chain = new ArrayList<ExpressionNode>(); |
||||
private final LogicalOperator operator; |
||||
|
||||
public static LogicalExpressionNode createLogicalOr(ExpressionNode left,ExpressionNode right){ |
||||
return new LogicalExpressionNode(left, LogicalOperator.OR, right); |
||||
} |
||||
|
||||
public static LogicalExpressionNode createLogicalAnd(ExpressionNode left,ExpressionNode right){ |
||||
return new LogicalExpressionNode(left, LogicalOperator.AND, right); |
||||
} |
||||
|
||||
private LogicalExpressionNode(ExpressionNode left, LogicalOperator operator, ExpressionNode right) { |
||||
chain.add(left); |
||||
chain.add(right); |
||||
this.operator = operator; |
||||
} |
||||
|
||||
public LogicalExpressionNode and(LogicalExpressionNode other){ |
||||
return createLogicalAnd(this, other); |
||||
} |
||||
|
||||
public LogicalExpressionNode or(LogicalExpressionNode other){ |
||||
return createLogicalOr(this, other); |
||||
} |
||||
|
||||
public LogicalOperator getOperator() { |
||||
return operator; |
||||
} |
||||
|
||||
public LogicalExpressionNode append(ExpressionNode expressionNode) { |
||||
chain.add(expressionNode); |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
//return "(" + Utils.join(" " + operator.getOperatorString() + " ", Utils.reverse(chain)) + ")";
|
||||
return "(" + Utils.join(" " + operator.getOperatorString() + " ", chain) + ")"; |
||||
} |
||||
|
||||
@Override |
||||
public boolean apply(PredicateContext ctx) { |
||||
if(operator == LogicalOperator.OR){ |
||||
for (ExpressionNode expression : chain) { |
||||
if(expression.apply(ctx)){ |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} else { |
||||
for (ExpressionNode expression : chain) { |
||||
if(!expression.apply(ctx)){ |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,30 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.InvalidPathException; |
||||
|
||||
public enum LogicalOperator { |
||||
|
||||
AND("&&"), |
||||
OR("||"); |
||||
|
||||
private final String operatorString; |
||||
|
||||
LogicalOperator(String operatorString) { |
||||
this.operatorString = operatorString; |
||||
} |
||||
|
||||
public String getOperatorString() { |
||||
return operatorString; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return operatorString; |
||||
} |
||||
|
||||
public static LogicalOperator fromString(String operatorString){ |
||||
if(AND.operatorString.equals(operatorString)) return AND; |
||||
else if(OR.operatorString.equals(operatorString)) return OR; |
||||
else throw new InvalidPathException("Failed to parse operator " + operatorString); |
||||
} |
||||
} |
@ -0,0 +1,111 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
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.internal.Path; |
||||
import com.jayway.jsonpath.internal.PathCompiler; |
||||
import com.jayway.jsonpath.internal.token.PredicateContextImpl; |
||||
import com.jayway.jsonpath.spi.json.JsonProvider; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import java.math.BigDecimal; |
||||
|
||||
public class PathNode extends ValueNode { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PathNode.class); |
||||
|
||||
private final Path path; |
||||
private final boolean existsCheck; |
||||
private final boolean shouldExist; |
||||
|
||||
public PathNode(Path path) { |
||||
this(path, false, false); |
||||
} |
||||
|
||||
public PathNode(CharSequence charSequence, boolean existsCheck, boolean shouldExist) { |
||||
this(PathCompiler.compile(charSequence.toString()), existsCheck, shouldExist); |
||||
} |
||||
|
||||
public PathNode(Path path, boolean existsCheck, boolean shouldExist) { |
||||
this.path = path; |
||||
this.existsCheck = existsCheck; |
||||
this.shouldExist = shouldExist; |
||||
logger.trace("PathNode {} existsCheck: {}", path, existsCheck); |
||||
} |
||||
|
||||
public Path getPath() { |
||||
return path; |
||||
} |
||||
|
||||
public boolean isExistsCheck() { |
||||
return existsCheck; |
||||
} |
||||
|
||||
public boolean shouldExists() { |
||||
return shouldExist; |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Void.class; |
||||
} |
||||
|
||||
public boolean isPathNode() { |
||||
return true; |
||||
} |
||||
|
||||
public PathNode asPathNode() { |
||||
return this; |
||||
} |
||||
|
||||
public PathNode asExistsCheck(boolean shouldExist) { |
||||
return new PathNode(path, true, shouldExist); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return path.toString(); |
||||
} |
||||
|
||||
public ValueNode evaluate(Predicate.PredicateContext ctx) { |
||||
Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options(Option.REQUIRE_PROPERTIES).build(); |
||||
if (isExistsCheck()) { |
||||
try { |
||||
Object result = path.evaluate(ctx.item(), ctx.root(), c).getValue(false); |
||||
return result == JsonProvider.UNDEFINED ? ValueNode.FALSE : ValueNode.TRUE; |
||||
} catch (PathNotFoundException e) { |
||||
return ValueNode.FALSE; |
||||
} |
||||
} else { |
||||
try { |
||||
Object res; |
||||
if (ctx instanceof PredicateContextImpl) { |
||||
//This will use cache for document ($) queries
|
||||
PredicateContextImpl ctxi = (PredicateContextImpl) ctx; |
||||
res = ctxi.evaluate(path); |
||||
} else { |
||||
Object doc = path.isRootPath() ? ctx.root() : ctx.item(); |
||||
res = path.evaluate(doc, ctx.root(), ctx.configuration()).getValue(); |
||||
} |
||||
res = ctx.configuration().jsonProvider().unwrap(res); |
||||
|
||||
if (res instanceof Number) return ValueNode.createNumberNode(res.toString()); |
||||
else if (res instanceof BigDecimal) return ValueNode.createNumberNode(res.toString()); |
||||
else if (res instanceof String) return ValueNode.createStringNode(res.toString(), false); |
||||
else if (res instanceof Boolean) return ValueNode.createBooleanNode(res.toString()); |
||||
else if (res == null) return ValueNode.NULL_NODE; |
||||
else if (ctx.configuration().jsonProvider().isArray(res)) return ValueNode.createJsonNode(res); |
||||
else if (ctx.configuration().jsonProvider().isMap(res)) return ValueNode.createJsonNode(res); |
||||
else throw new JsonPathException("Could not convert " + res.toString() + " to a ValueNode"); |
||||
} catch (PathNotFoundException e) { |
||||
return ValueNode.UNDEFINED; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,48 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class RelationalExpressionNode extends ExpressionNode { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RelationalExpressionNode.class); |
||||
|
||||
private final ValueNode left; |
||||
private final RelationalOperator relationalOperator; |
||||
private final ValueNode right; |
||||
|
||||
public RelationalExpressionNode(ValueNode left, RelationalOperator relationalOperator, ValueNode right) { |
||||
this.left = left; |
||||
this.relationalOperator = relationalOperator; |
||||
this.right = right; |
||||
|
||||
logger.trace("ExpressionNode {}", toString()); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
if(relationalOperator == RelationalOperator.EXISTS){ |
||||
return left.toString(); |
||||
} else { |
||||
return left.toString() + " " + relationalOperator.toString() + " " + right.toString(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean apply(PredicateContext ctx) { |
||||
ValueNode l = left; |
||||
ValueNode r = right; |
||||
|
||||
if(left.isPathNode()){ |
||||
l = left.asPathNode().evaluate(ctx); |
||||
} |
||||
if(right.isPathNode()){ |
||||
r = right.asPathNode().evaluate(ctx); |
||||
} |
||||
Evaluator evaluator = EvaluatorFactory.createEvaluator(relationalOperator); |
||||
if(evaluator != null){ |
||||
return evaluator.evaluate(l, r, ctx); |
||||
} |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,47 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.InvalidPathException; |
||||
|
||||
public enum RelationalOperator { |
||||
|
||||
GTE(">="), |
||||
LTE("<="), |
||||
EQ("=="), |
||||
NE("!="), |
||||
LT("<"), |
||||
GT(">"), |
||||
REGEX("=~"), |
||||
NIN("¦NIN¦"), |
||||
IN("¦IN¦"), |
||||
CONTAINS("¦CONTAINS¦"), |
||||
ALL("¦ALL¦"), |
||||
SIZE("¦SIZE¦"), |
||||
EXISTS("¦EXISTS¦"), |
||||
TYPE("¦TYPE¦"), |
||||
MATCHES("¦MATCHES¦"), |
||||
NOT_EMPTY("¦NOT_EMPTY¦"); |
||||
|
||||
private final String operatorString; |
||||
|
||||
RelationalOperator(String operatorString) { |
||||
this.operatorString = operatorString; |
||||
} |
||||
|
||||
public String getOperatorString() { |
||||
return operatorString; |
||||
} |
||||
|
||||
public static RelationalOperator fromString(String operatorString){ |
||||
for (RelationalOperator operator : RelationalOperator.values()) { |
||||
if(operator.operatorString.equals(operatorString) ){ |
||||
return operator; |
||||
} |
||||
} |
||||
throw new InvalidPathException("Operator not supported " + operatorString); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return operatorString; |
||||
} |
||||
} |
@ -0,0 +1,700 @@
|
||||
package com.jayway.jsonpath.internal.filter; |
||||
|
||||
import com.jayway.jsonpath.Configuration; |
||||
import com.jayway.jsonpath.InvalidPathException; |
||||
import com.jayway.jsonpath.JsonPathException; |
||||
import com.jayway.jsonpath.Predicate; |
||||
import com.jayway.jsonpath.internal.PathCompiler; |
||||
import com.jayway.jsonpath.internal.Utils; |
||||
|
||||
import java.math.BigDecimal; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.regex.Pattern; |
||||
|
||||
public abstract class ValueNode { |
||||
|
||||
public static final NullNode NULL_NODE = new NullNode(); |
||||
public static final BooleanNode TRUE = new BooleanNode("true"); |
||||
public static final BooleanNode FALSE = new BooleanNode("false"); |
||||
public static final UndefinedNode UNDEFINED = new UndefinedNode(); |
||||
|
||||
|
||||
public abstract Class<?> type(Predicate.PredicateContext ctx); |
||||
|
||||
public boolean isPatternNode() { |
||||
return false; |
||||
} |
||||
|
||||
public PatternNode asPatternNode() { |
||||
throw new InvalidPathException("Expected regexp node"); |
||||
} |
||||
|
||||
public boolean isPathNode() { |
||||
return false; |
||||
} |
||||
|
||||
public PathNode asPathNode() { |
||||
throw new InvalidPathException("Expected path node"); |
||||
} |
||||
|
||||
public boolean isNumberNode() { |
||||
return false; |
||||
} |
||||
|
||||
public NumberNode asNumberNode() { |
||||
throw new InvalidPathException("Expected number node"); |
||||
} |
||||
|
||||
public boolean isStringNode() { |
||||
return false; |
||||
} |
||||
|
||||
public StringNode asStringNode() { |
||||
throw new InvalidPathException("Expected string node"); |
||||
} |
||||
|
||||
public boolean isBooleanNode() { |
||||
return false; |
||||
} |
||||
|
||||
public BooleanNode asBooleanNode() { |
||||
throw new InvalidPathException("Expected boolean node"); |
||||
} |
||||
|
||||
public boolean isJsonNode() { |
||||
return false; |
||||
} |
||||
|
||||
public JsonNode asJsonNode() { |
||||
throw new InvalidPathException("Expected json node"); |
||||
} |
||||
|
||||
public boolean isPredicateNode() { |
||||
return false; |
||||
} |
||||
|
||||
public PredicateNode asPredicateNode() { |
||||
throw new InvalidPathException("Expected predicate node"); |
||||
} |
||||
|
||||
public boolean isValueListNode() { |
||||
return false; |
||||
} |
||||
|
||||
public ValueListNode asValueListNode() { |
||||
throw new InvalidPathException("Expected value list node"); |
||||
} |
||||
|
||||
public boolean isNullNode() { |
||||
return false; |
||||
} |
||||
|
||||
public NullNode asNullNode() { |
||||
throw new InvalidPathException("Expected null node"); |
||||
} |
||||
|
||||
public UndefinedNode asUndefinedNode() { |
||||
throw new InvalidPathException("Expected undefined node"); |
||||
} |
||||
|
||||
public boolean isUndefinedNode() { |
||||
return false; |
||||
} |
||||
|
||||
public boolean isClassNode() { |
||||
return false; |
||||
} |
||||
|
||||
public ClassNode asClassNode() { |
||||
throw new InvalidPathException("Expected class node"); |
||||
} |
||||
|
||||
private static boolean isPath(Object o) { |
||||
if(o == null || !(o instanceof String)){ |
||||
return false; |
||||
} |
||||
String str = o.toString().trim(); |
||||
if (str.length() <= 0) { |
||||
return false; |
||||
} |
||||
char c0 = str.charAt(0); |
||||
if(c0 == '@' || c0 == '$'){ |
||||
try { |
||||
PathCompiler.compile(str); |
||||
return true; |
||||
} catch(Exception e){ |
||||
return false; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private static boolean isJson(Object o) { |
||||
if(o == null || !(o instanceof String)){ |
||||
return false; |
||||
} |
||||
String str = o.toString().trim(); |
||||
if (str.length() <= 1) { |
||||
return false; |
||||
} |
||||
char c0 = str.charAt(0); |
||||
char c1 = str.charAt(str.length() - 1); |
||||
if ((c0 == '[' && c1 == ']') || (c0 == '{' && c1 == '}')){ |
||||
try { |
||||
Configuration.defaultConfiguration().jsonProvider().parse(str); |
||||
return false; |
||||
} catch(Exception e){ |
||||
return false; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
|
||||
//----------------------------------------------------
|
||||
//
|
||||
// Factory methods
|
||||
//
|
||||
//----------------------------------------------------
|
||||
public static ValueNode toValueNode(Object o){ |
||||
if(o == null) return ValueNode.NULL_NODE; |
||||
if(o instanceof ValueNode) return (ValueNode)o; |
||||
if(o instanceof Class) return createClassNode((Class)o); |
||||
else if(isPath(o)) return new PathNode(o.toString(), false, false); |
||||
else if(isJson(o)) return createStringNode(o.toString(), false); |
||||
else if(o instanceof String) return createStringNode(o.toString(), false); |
||||
else if(o instanceof Character) return createStringNode(o.toString(), false); |
||||
else if(o instanceof Number) return createNumberNode(o.toString()); |
||||
else if(o instanceof Boolean) return createBooleanNode(o.toString()); |
||||
else if(o instanceof Pattern) return createPatternNode((Pattern)o); |
||||
else throw new JsonPathException("Could not determine value type"); |
||||
} |
||||
|
||||
public static StringNode createStringNode(CharSequence charSequence, boolean escape){ |
||||
return new StringNode(charSequence, escape); |
||||
} |
||||
|
||||
public static ClassNode createClassNode(Class<?> clazz){ |
||||
return new ClassNode(clazz); |
||||
} |
||||
|
||||
public static NumberNode createNumberNode(CharSequence charSequence){ |
||||
return new NumberNode(charSequence); |
||||
} |
||||
|
||||
public static BooleanNode createBooleanNode(CharSequence charSequence){ |
||||
return Boolean.parseBoolean(charSequence.toString()) ? TRUE : FALSE; |
||||
} |
||||
|
||||
public static NullNode createNullNode(){ |
||||
return NULL_NODE; |
||||
} |
||||
|
||||
public static JsonNode createJsonNode(CharSequence json) { |
||||
return new JsonNode(json); |
||||
} |
||||
|
||||
public static JsonNode createJsonNode(Object parsedJson) { |
||||
return new JsonNode(parsedJson); |
||||
} |
||||
|
||||
public static PatternNode createPatternNode(CharSequence pattern) { |
||||
return new PatternNode(pattern); |
||||
} |
||||
|
||||
public static PatternNode createPatternNode(Pattern pattern) { |
||||
return new PatternNode(pattern); |
||||
} |
||||
|
||||
public static UndefinedNode createUndefinedNode() { |
||||
return UNDEFINED; |
||||
} |
||||
|
||||
//----------------------------------------------------
|
||||
//
|
||||
// ValueNode Implementations
|
||||
//
|
||||
//----------------------------------------------------
|
||||
public static class PatternNode extends ValueNode { |
||||
private final String pattern; |
||||
private final Pattern compiledPattern; |
||||
|
||||
private PatternNode(CharSequence charSequence) { |
||||
String tmp = charSequence.toString(); |
||||
int begin = tmp.indexOf('/'); |
||||
int end = tmp.lastIndexOf('/'); |
||||
int flags = tmp.endsWith("/i") ? Pattern.CASE_INSENSITIVE : 0; |
||||
this.pattern = tmp.substring(begin + 1, end); |
||||
this.compiledPattern = Pattern.compile(pattern, flags); |
||||
} |
||||
|
||||
public PatternNode(Pattern pattern) { |
||||
this.pattern = pattern.pattern(); |
||||
this.compiledPattern = pattern; |
||||
} |
||||
|
||||
public String getPattern() { |
||||
return "/" + pattern + "/"; |
||||
} |
||||
|
||||
public Pattern getCompiledPattern() { |
||||
return compiledPattern; |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Void.TYPE; |
||||
} |
||||
|
||||
public boolean isPatternNode() { |
||||
return true; |
||||
} |
||||
|
||||
public PatternNode asPatternNode() { |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return pattern; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof PatternNode)) return false; |
||||
|
||||
PatternNode that = (PatternNode) o; |
||||
|
||||
return !(compiledPattern != null ? !compiledPattern.equals(that.compiledPattern) : that.compiledPattern != null); |
||||
|
||||
} |
||||
} |
||||
|
||||
public static class JsonNode extends ValueNode { |
||||
private final Object json; |
||||
private final boolean parsed; |
||||
|
||||
private JsonNode(CharSequence charSequence) { |
||||
json = charSequence.toString(); |
||||
parsed = false; |
||||
} |
||||
|
||||
public JsonNode(Object parsedJson) { |
||||
json = parsedJson; |
||||
parsed = true; |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
if(ctx.configuration().jsonProvider().isArray(parse(ctx))) return List.class; |
||||
else if(ctx.configuration().jsonProvider().isMap(parse(ctx))) return Map.class; |
||||
else if(ctx.configuration().jsonProvider().unwrap(parse(ctx)) instanceof Number) return Number.class; |
||||
else if(ctx.configuration().jsonProvider().unwrap(parse(ctx)) instanceof String) return String.class; |
||||
else if(ctx.configuration().jsonProvider().unwrap(parse(ctx)) instanceof Boolean) return Boolean.class; |
||||
else return Void.class; |
||||
} |
||||
|
||||
public boolean isJsonNode() { |
||||
return true; |
||||
} |
||||
|
||||
public JsonNode asJsonNode() { |
||||
return this; |
||||
} |
||||
|
||||
public ValueNode asValueListNode(Predicate.PredicateContext ctx){ |
||||
if(!isArray(ctx)){ |
||||
return UNDEFINED; |
||||
} else { |
||||
Collection nodes = new ArrayList(); |
||||
for (Object value : ctx.configuration().jsonProvider().toIterable(parse(ctx))) { |
||||
nodes.add(value); |
||||
} |
||||
return new ValueListNode(nodes); |
||||
} |
||||
} |
||||
|
||||
public Object parse(Predicate.PredicateContext ctx){ |
||||
return parsed ? json : ctx.configuration().jsonProvider().parse(json.toString()); |
||||
} |
||||
|
||||
public boolean isParsed() { |
||||
return parsed; |
||||
} |
||||
|
||||
public Object getJson() { |
||||
return json; |
||||
} |
||||
|
||||
public boolean isArray(Predicate.PredicateContext ctx) { |
||||
return ctx.configuration().jsonProvider().isArray(parse(ctx)); |
||||
} |
||||
|
||||
public boolean isMap(Predicate.PredicateContext ctx) { |
||||
return ctx.configuration().jsonProvider().isArray(parse(ctx)); |
||||
} |
||||
|
||||
public int length(Predicate.PredicateContext ctx) { |
||||
return isArray(ctx) ? ctx.configuration().jsonProvider().length(parse(ctx)) : -1; |
||||
} |
||||
|
||||
public boolean isEmpty(Predicate.PredicateContext ctx) { |
||||
if(isArray(ctx) || isMap(ctx)) return ctx.configuration().jsonProvider().length(parse(ctx)) == 0; |
||||
else if((parse(ctx) instanceof String)) return ((String)parse(ctx)).length() == 0; |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return json.toString(); |
||||
} |
||||
|
||||
public boolean equals(JsonNode jsonNode, Predicate.PredicateContext ctx) { |
||||
if (this == jsonNode) return true; |
||||
return !(json != null ? !json.equals(jsonNode.parse(ctx)) : jsonNode.json != null); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof JsonNode)) return false; |
||||
|
||||
JsonNode jsonNode = (JsonNode) o; |
||||
|
||||
return !(json != null ? !json.equals(jsonNode.json) : jsonNode.json != null); |
||||
} |
||||
} |
||||
|
||||
public static class StringNode extends ValueNode { |
||||
private final String string; |
||||
|
||||
private StringNode(CharSequence charSequence, boolean escape) { |
||||
if(charSequence.length() > 1){ |
||||
if(charSequence.charAt(0) == '\'' && charSequence.charAt(charSequence.length()-1) == '\''){ |
||||
charSequence = charSequence.subSequence(1, charSequence.length()-1); |
||||
} |
||||
} |
||||
string = escape ? Utils.unescape(charSequence.toString()) : charSequence.toString(); |
||||
} |
||||
|
||||
public String getString() { |
||||
return string; |
||||
} |
||||
|
||||
public int length(){ |
||||
return getString().length(); |
||||
} |
||||
|
||||
public boolean isEmpty(){ |
||||
return getString().isEmpty(); |
||||
} |
||||
|
||||
public boolean contains(String str) { |
||||
return getString().contains(str); |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return String.class; |
||||
} |
||||
|
||||
public boolean isStringNode() { |
||||
return true; |
||||
} |
||||
|
||||
public StringNode asStringNode() { |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "'" + string + "'"; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof StringNode)) return false; |
||||
|
||||
StringNode that = (StringNode) o; |
||||
|
||||
return !(string != null ? !string.equals(that.string) : that.string != null); |
||||
|
||||
} |
||||
} |
||||
|
||||
public static class NumberNode extends ValueNode { |
||||
private final BigDecimal number; |
||||
|
||||
private NumberNode(CharSequence num) { |
||||
number = new BigDecimal(num.toString()); |
||||
} |
||||
|
||||
public BigDecimal getNumber() { |
||||
return number; |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Number.class; |
||||
} |
||||
|
||||
public boolean isNumberNode() { |
||||
return true; |
||||
} |
||||
|
||||
public NumberNode asNumberNode() { |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return number.toString(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof NumberNode)) return false; |
||||
|
||||
ValueNode that = (ValueNode) o; |
||||
|
||||
if(!that.isNumberNode()){ |
||||
return false; |
||||
} else { |
||||
return number.compareTo(that.asNumberNode().number) == 0; |
||||
} |
||||
} |
||||
} |
||||
|
||||
public static class BooleanNode extends ValueNode { |
||||
private final Boolean value; |
||||
|
||||
private BooleanNode(CharSequence boolValue) { |
||||
value = Boolean.parseBoolean(boolValue.toString()); |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Boolean.class; |
||||
} |
||||
|
||||
public boolean isBooleanNode() { |
||||
return true; |
||||
} |
||||
|
||||
public BooleanNode asBooleanNode() { |
||||
return this; |
||||
} |
||||
|
||||
public boolean getBoolean() { |
||||
return value; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return value.toString(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof BooleanNode)) return false; |
||||
|
||||
BooleanNode that = (BooleanNode) o; |
||||
|
||||
return !(value != null ? !value.equals(that.value) : that.value != null); |
||||
} |
||||
} |
||||
|
||||
public static class ClassNode extends ValueNode { |
||||
private final Class clazz; |
||||
|
||||
private ClassNode(Class clazz) { |
||||
this.clazz = clazz; |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Class.class; |
||||
} |
||||
|
||||
public boolean isClassNode() { |
||||
return true; |
||||
} |
||||
|
||||
public ClassNode asClassNode() { |
||||
return this; |
||||
} |
||||
|
||||
public Class getClazz() { |
||||
return clazz; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return clazz.getName(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof ClassNode)) return false; |
||||
|
||||
ClassNode that = (ClassNode) o; |
||||
|
||||
return !(clazz != null ? !clazz.equals(that.clazz) : that.clazz != null); |
||||
} |
||||
} |
||||
|
||||
public static class NullNode extends ValueNode { |
||||
|
||||
private NullNode() {} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Void.class; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isNullNode() { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public NullNode asNullNode() { |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "null"; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof NullNode)) return false; |
||||
|
||||
return true; |
||||
} |
||||
} |
||||
|
||||
public static class UndefinedNode extends ValueNode { |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Void.class; |
||||
} |
||||
|
||||
public UndefinedNode asUndefinedNode() { |
||||
return this; |
||||
} |
||||
|
||||
public boolean isUndefinedNode() { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public static class PredicateNode extends ValueNode { |
||||
|
||||
private final Predicate predicate; |
||||
|
||||
public PredicateNode(Predicate predicate) { |
||||
this.predicate = predicate; |
||||
} |
||||
|
||||
public Predicate getPredicate() { |
||||
return predicate; |
||||
} |
||||
|
||||
public PredicateNode asPredicateNode() { |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return Void.class; |
||||
} |
||||
|
||||
public boolean isPredicateNode() { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return predicate.toString(); |
||||
} |
||||
} |
||||
|
||||
public static class ValueListNode extends ValueNode implements Iterable<ValueNode> { |
||||
|
||||
private List<ValueNode> nodes = new ArrayList<ValueNode>(); |
||||
|
||||
public ValueListNode(Collection<?> values) { |
||||
for (Object value : values) { |
||||
nodes.add(toValueNode(value)); |
||||
} |
||||
} |
||||
|
||||
public boolean contains(ValueNode node){ |
||||
return nodes.contains(node); |
||||
} |
||||
|
||||
public List<ValueNode> getNodes() { |
||||
return Collections.unmodifiableList(nodes); |
||||
} |
||||
|
||||
@Override |
||||
public Class<?> type(Predicate.PredicateContext ctx) { |
||||
return List.class; |
||||
} |
||||
|
||||
public boolean isValueListNode() { |
||||
return true; |
||||
} |
||||
|
||||
public ValueListNode asValueListNode() { |
||||
return this; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "[" + Utils.join(",", nodes) + "]"; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) return true; |
||||
if (!(o instanceof ValueListNode)) return false; |
||||
|
||||
ValueListNode that = (ValueListNode) o; |
||||
|
||||
return !(that != null ? !nodes.equals(that.nodes) : that.nodes != null); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<ValueNode> iterator() { |
||||
return nodes.iterator(); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,61 @@
|
||||
package com.jayway.jsonpath; |
||||
|
||||
import com.jayway.jsonpath.internal.filter.FilterCompiler; |
||||
import org.junit.Test; |
||||
|
||||
public class FilterCompilerTest { |
||||
|
||||
|
||||
@Test |
||||
public void filter_compiler_test() { |
||||
/* |
||||
FilterCompiler.compile("[?(@)]"); |
||||
|
||||
FilterCompiler.compile("[?($)]"); |
||||
|
||||
FilterCompiler.compile("[?(@.firstname)]"); |
||||
FilterCompiler.compile("[?(@.firstname)]"); |
||||
FilterCompiler.compile("[?($.firstname)]"); |
||||
FilterCompiler.compile("[?(@['firstname'])]"); |
||||
|
||||
|
||||
FilterCompiler.compile("[?($['firstname'].lastname)]"); |
||||
FilterCompiler.compile("[?($['firstname']['lastname'])]"); |
||||
|
||||
FilterCompiler.compile("[?($['firstname']['lastname'].*)]"); |
||||
|
||||
FilterCompiler.compile("[?($['firstname']['num_eq'] == 1)]"); |
||||
FilterCompiler.compile("[?($['firstname']['num_gt'] > 1.1)]"); |
||||
|
||||
FilterCompiler.compile("[?($['firstname']['num_lt'] < 11.11)]"); |
||||
FilterCompiler.compile("[?($['firstname']['num_in'] ¦IN¦ 0.1)]"); |
||||
|
||||
FilterCompiler.compile("[?($['firstname']['str_eq'] == 'hej')]"); |
||||
FilterCompiler.compile("[?($['firstname']['str_eq'] == '')]"); |
||||
|
||||
FilterCompiler.compile("[?($['firstname']['str_eq'] == null)]"); |
||||
FilterCompiler.compile("[?($['firstname']['str_eq'] == true)]"); |
||||
FilterCompiler.compile("[?($['firstname']['str_eq'] == false)]"); |
||||
|
||||
|
||||
FilterCompiler.compile("[?(@.firstname && @.lastname)]"); |
||||
FilterCompiler.compile("[?((@.firstname || @.lastname) && @.and)]"); |
||||
|
||||
FilterCompiler.compile("[?((@.a || @.b || @.c) && @.x)]"); |
||||
FilterCompiler.compile("[?((@.a && @.b && @.c) || @.x)]"); |
||||
FilterCompiler.compile("[?((@.a && @.b || @.c) || @.x)]"); |
||||
FilterCompiler.compile("[?((@.a && @.b) || (@.c && @.d))]"); |
||||
|
||||
|
||||
FilterCompiler.compile("[?(@.a ¦IN¦ [1,2,3])]"); |
||||
FilterCompiler.compile("[?(@.a ¦IN¦ {'foo':'bar'})]"); |
||||
FilterCompiler.compile("[?(@.value<'7')]"); |
||||
*/ |
||||
|
||||
//FilterCompiler.compile("[?(@.message == 'it\\'s here')]");
|
||||
FilterCompiler.compile("[?(@.message == 'it\\\\')]"); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
Loading…
Reference in new issue