diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index c0e8e8d3..c965ce58 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -20,7 +20,6 @@ public class FilterCompiler { 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 = '='; @@ -134,16 +133,17 @@ public class FilterCompiler { private RelationalExpressionNode readExpression() { ValueNode left = readValueNode(); - if (left.isPathNode()) { - final PathNode pathNode = left.asPathNode(); - if (pathNode.isExistsCheck()) { - return new RelationalExpressionNode(pathNode, RelationalOperator.EXISTS, pathNode.shouldExists() ? ValueNode.TRUE : ValueNode.FALSE); - } + if(expressionIsTerminated()) { + PathNode pathNode = left.asPathNode(); + left = pathNode.asExistsCheck(pathNode.shouldExists()); + RelationalOperator operator = RelationalOperator.EXISTS; + ValueNode right = left.asPathNode().shouldExists() ? ValueNode.TRUE : ValueNode.FALSE; + return new RelationalExpressionNode(left, operator, right); + } else { + RelationalOperator operator = readRelationalOperator(); + ValueNode right = readValueNode(); + return new RelationalExpressionNode(left, operator, right); } - RelationalOperator operator = readRelationalOperator(); - ValueNode right = readValueNode(); - - return new RelationalExpressionNode(left, operator, right); } private LogicalOperator readLogicalOperator(){ @@ -166,18 +166,16 @@ public class FilterCompiler { 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); + if(isRelationalOperatorChar(filter.currentChar())){ + while (filter.inBounds() && isRelationalOperatorChar(filter.currentChar())) { + filter.incrementPosition(1); } } else { - while (filter.inBounds() && isRelationalOperatorChar(filter.currentChar())) { + while (filter.inBounds() && filter.currentChar() != SPACE) { 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()); @@ -277,7 +275,6 @@ public class FilterCompiler { private PathNode readPath() { char previousSignificantChar = filter.previousSignificantChar(); - boolean operatorOnLeft = isRelationalOperatorChar(previousSignificantChar) && previousSignificantChar != BANG; int begin = filter.position(); filter.incrementPosition(1); //skip $ and @ @@ -297,14 +294,22 @@ public class FilterCompiler { filter.incrementPosition(1); } } - boolean operatorOnRight = isRelationalOperatorChar(filter.currentChar()) || isRelationalOperatorChar(filter.nextSignificantChar()); - boolean existsCheck = !operatorOnLeft && !operatorOnRight; - boolean shouldExists = true; - if(existsCheck){ - shouldExists = !(previousSignificantChar == BANG); - } + + boolean shouldExists = !(previousSignificantChar == BANG); CharSequence path = filter.subSequence(begin, filter.position()); - return new PathNode(path, existsCheck, shouldExists); + return new PathNode(path, false, shouldExists); + } + + private boolean expressionIsTerminated(){ + char c = filter.currentChar(); + if(c == CLOSE_BRACKET || isLogicalOperatorChar(c)){ + return true; + } + c = filter.nextSignificantChar(); + if(c == CLOSE_BRACKET || isLogicalOperatorChar(c)){ + return true; + } + return false; } private boolean currentCharIsClosingFunctionBracket(int lowerBound){ @@ -325,7 +330,10 @@ public class FilterCompiler { return false; } + private boolean isLogicalOperatorChar(char c) { + return c == AND || c == OR; + } private boolean isRelationalOperatorChar(char c) { - return c == OPERATOR_PIPE || c == LT || c == GT || c == EQ || c == TILDE || c == BANG; + return c == LT || c == GT || c == EQ || c == TILDE || c == BANG; } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java index 4d009957..327f4f31 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java @@ -42,7 +42,6 @@ public class LogicalExpressionNode extends ExpressionNode { @Override public String toString() { - //return "(" + Utils.join(" " + operator.getOperatorString() + " ", Utils.reverse(chain)) + ")"; return "(" + Utils.join(" " + operator.getOperatorString() + " ", chain) + ")"; } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/RelationalOperator.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/RelationalOperator.java index 37e43e81..d3ebbc36 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/RelationalOperator.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/RelationalOperator.java @@ -11,15 +11,15 @@ public enum RelationalOperator { LT("<"), GT(">"), REGEX("=~"), - NIN("¦NIN¦"), - IN("¦IN¦"), - CONTAINS("¦CONTAINS¦"), - ALL("¦ALL¦"), - SIZE("¦SIZE¦"), - EXISTS("¦EXISTS¦"), - TYPE("¦TYPE¦"), - MATCHES("¦MATCHES¦"), - EMPTY("¦EMPTY¦"); + NIN("NIN"), + IN("IN"), + CONTAINS("CONTAINS"), + ALL("ALL"), + SIZE("SIZE"), + EXISTS("EXISTS"), + TYPE("TYPE"), + MATCHES("MATCHES"), + EMPTY("EMPTY"); private final String operatorString; @@ -27,13 +27,9 @@ public enum RelationalOperator { this.operatorString = operatorString; } - public String getOperatorString() { - return operatorString; - } - public static RelationalOperator fromString(String operatorString){ for (RelationalOperator operator : RelationalOperator.values()) { - if(operator.operatorString.equals(operatorString) ){ + if(operator.operatorString.equals(operatorString.toUpperCase()) ){ return operator; } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java b/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java index 956765d7..e50fc212 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java @@ -5,10 +5,9 @@ import org.junit.Test; public class FilterCompilerTest { - @Test public void filter_compiler_test() { - /* + FilterCompiler.compile("[?(@)]"); FilterCompiler.compile("[?($)]"); @@ -28,7 +27,6 @@ public class FilterCompilerTest { 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'] == '')]"); @@ -47,15 +45,10 @@ public class FilterCompilerTest { FilterCompiler.compile("[?((@.a && @.b) || (@.c && @.d))]"); - FilterCompiler.compile("[?(@.a ¦IN¦ [1,2,3])]"); - FilterCompiler.compile("[?(@.a ¦IN¦ {'foo':'bar'})]"); + 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\\\\')]"); - } - - } diff --git a/json-path/src/test/java/com/jayway/jsonpath/FilterParseTest.java b/json-path/src/test/java/com/jayway/jsonpath/FilterParseTest.java index ce24838a..a073d9b1 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/FilterParseTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/FilterParseTest.java @@ -102,7 +102,7 @@ public class FilterParseTest { @Test public void a_nin_filter_can_be_serialized() { String filter = filter(where("a").nin(1)).toString(); - String parsed = parse("[?(@['a'] ¦NIN¦ [1])]").toString(); + String parsed = parse("[?(@['a'] NIN [1])]").toString(); assertThat(filter).isEqualTo(parsed); } @@ -111,7 +111,7 @@ public class FilterParseTest { public void a_in_filter_can_be_serialized() { String filter = filter(where("a").in("a")).toString(); - String parsed = parse("[?(@['a'] ¦IN¦ ['a'])]").toString(); + String parsed = parse("[?(@['a'] IN ['a'])]").toString(); assertThat(filter).isEqualTo(parsed); } @@ -119,7 +119,7 @@ public class FilterParseTest { @Test public void a_contains_filter_can_be_serialized() { String filter = filter(where("a").contains("a")).toString(); - String parsed = parse("[?(@['a'] ¦CONTAINS¦ 'a')]").toString(); + String parsed = parse("[?(@['a'] CONTAINS 'a')]").toString(); assertThat(filter).isEqualTo(parsed); } @@ -128,7 +128,7 @@ public class FilterParseTest { public void a_all_filter_can_be_serialized() { String filter = filter(where("a").all("a", "b")).toString(); - String parsed = parse("[?(@['a'] ¦ALL¦ ['a','b'])]").toString(); + String parsed = parse("[?(@['a'] ALL ['a','b'])]").toString(); assertThat(filter).isEqualTo(parsed); } @@ -137,7 +137,7 @@ public class FilterParseTest { public void a_size_filter_can_be_serialized() { String filter = filter(where("a").size(5)).toString(); - String parsed = parse("[?(@['a'] ¦SIZE¦ 5)]").toString(); + String parsed = parse("[?(@['a'] SIZE 5)]").toString(); assertThat(filter).isEqualTo(parsed); } @@ -163,21 +163,21 @@ public class FilterParseTest { @Test public void a_type_filter_can_be_serialized() { - assertThat(filter(where("a").type(String.class)).toString()).isEqualTo("[?(@['a'] ¦TYPE¦ java.lang.String)]"); + assertThat(filter(where("a").type(String.class)).toString()).isEqualTo("[?(@['a'] TYPE java.lang.String)]"); } @Test public void a_matches_filter_can_be_serialized() { Filter a = filter(where("x").eq(1000)); - assertThat(filter(where("a").matches(a)).toString()).isEqualTo("[?(@['a'] ¦MATCHES¦ [?(@['x'] == 1000)])]"); + assertThat(filter(where("a").matches(a)).toString()).isEqualTo("[?(@['a'] MATCHES [?(@['x'] == 1000)])]"); } @Test public void a_not_empty_filter_can_be_serialized() { String filter = filter(where("a").empty(false)).toString(); - String parsed = parse("[?(@['a'] ¦EMPTY¦ false)]").toString(); + String parsed = parse("[?(@['a'] EMPTY false)]").toString(); assertThat(filter).isEqualTo(parsed); } @@ -195,7 +195,7 @@ public class FilterParseTest { public void in_string_filter_can_be_serialized() { String filter = filter(where("a").in("1","2")).toString(); - String parsed = parse("[?(@['a'] ¦IN¦ ['1','2'])]").toString(); + String parsed = parse("[?(@['a'] IN ['1','2'])]").toString(); assertThat(filter).isEqualTo(parsed); } @@ -204,7 +204,7 @@ public class FilterParseTest { public void a_deep_path_filter_can_be_serialized() { String filter = filter(where("a.b.c").in("1", "2")).toString(); - String parsed = parse("[?(@['a']['b']['c'] ¦IN¦ ['1','2'])]").toString(); + String parsed = parse("[?(@['a']['b']['c'] IN ['1','2'])]").toString(); assertThat(filter).isEqualTo(parsed); }