From a83f32cababb6f7721fb99e3904ec3abff1e7d31 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Wed, 18 Sep 2013 23:17:33 +0200 Subject: [PATCH] 'AND' (&&) support in ArrayEvalFilter. --- .../internal/filter/ArrayEvalFilter.java | 43 +++++++++++++++---- .../internal/filter/FilterFactory.java | 5 +-- .../jayway/jsonpath/ExpressionEvalTest.java | 20 +++++++++ .../com/jayway/jsonpath/HttpProviderTest.java | 6 +-- .../java/com/jayway/jsonpath/IssuesTest.java | 3 -- .../internal/filter/ArrayEvalFilterTest.java | 39 +++++++++++------ 6 files changed, 85 insertions(+), 31 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java index 82f4d7e7..3577dda0 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilter.java @@ -29,13 +29,28 @@ import java.util.regex.Pattern; */ public class ArrayEvalFilter extends PathTokenFilter { - private static final Pattern PATTERN = Pattern.compile("\\[\\s?\\?\\(\\s?(@.*?)\\s?([!=<>]+)\\s?(.*?)\\s?\\)\\s?]"); + private static final Pattern CONDITION_STATEMENT_PATTERN = Pattern.compile("\\[\\s?\\?\\(.*?[!=<>]+.*?\\)\\s?]"); + private static final Pattern PATTERN = Pattern.compile("\\s?(@.*?)\\s?([!=<>]+)\\s?(.*?)\\s?"); - private final ConditionStatement conditionStatement; - public ArrayEvalFilter(ConditionStatement statement) { - super(statement.condition); - this.conditionStatement = statement; + + private ConditionStatement[] conditionStatements; + + public ArrayEvalFilter(String condition) { + super(condition); + + // [?(@.name == 'Luke Skywalker' && @.occupation == 'Farm boy')] + // [?(@.name == 'Luke Skywalker')] + + condition = condition.trim(); + condition = condition.substring(3, condition.length()-2); + + String[] split = condition.split("&&"); + + conditionStatements = new ConditionStatement[split.length]; + for(int i = 0; i < split.length; i++){ + conditionStatements[i] = createConditionStatement(split[i]); + } } @@ -51,7 +66,7 @@ public class ArrayEvalFilter extends PathTokenFilter { } Object result = jsonProvider.createArray(); for (Object item : src) { - if (isMatch(item, conditionStatement, configuration)) { + if (isMatch(item, configuration, conditionStatements)) { jsonProvider.setProperty(result, jsonProvider.length(result), item); } } @@ -68,10 +83,16 @@ public class ArrayEvalFilter extends PathTokenFilter { return true; } - private boolean isMatch(Object check, ConditionStatement conditionStatement, Configuration configuration) { + private boolean isMatch(Object check, Configuration configuration, ConditionStatement... conditionStatements) { try { - Object value = conditionStatement.path.read(check, configuration.options(Option.THROW_ON_MISSING_PROPERTY)); - return ExpressionEvaluator.eval(value, conditionStatement.getOperator(), conditionStatement.getExpected()); + for (ConditionStatement conditionStatement : conditionStatements) { + Object value = conditionStatement.path.read(check, configuration.options(Option.THROW_ON_MISSING_PROPERTY)); + boolean match = ExpressionEvaluator.eval(value, conditionStatement.getOperator(), conditionStatement.getExpected()); + if(!match){ + return false; + } + } + return true; } catch (PathNotFoundException e){ return false; } catch (RuntimeException e){ @@ -80,6 +101,10 @@ public class ArrayEvalFilter extends PathTokenFilter { } } + static boolean isConditionStatement(String condition) { + return CONDITION_STATEMENT_PATTERN.matcher(condition).matches(); + } + static ConditionStatement createConditionStatement(String condition) { Matcher matcher = PATTERN.matcher(condition); if (matcher.matches()) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterFactory.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterFactory.java index 8bc09ee3..bfd90374 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterFactory.java @@ -60,9 +60,8 @@ public class FilterFactory { if (pathFragment.startsWith("[?")) { - ArrayEvalFilter.ConditionStatement conditionStatement = ArrayEvalFilter.createConditionStatement(pathFragment); - if(conditionStatement != null){ - return new ArrayEvalFilter(conditionStatement); + if(ArrayEvalFilter.isConditionStatement(pathFragment)){ + return new ArrayEvalFilter(pathFragment); } else if (!pathFragment.contains("=") && !pathFragment.contains("<") && !pathFragment.contains(">")) { //[?(@.isbn)] return new HasFieldFilter(pathFragment); diff --git a/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java b/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java index 10432851..f7fb5d76 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java @@ -189,6 +189,26 @@ public class ExpressionEvalTest { assertTrue(ExpressionEvaluator.eval(null, "!=", "10")); } + @Test + public void and_operator_in_filter() { + + Object o = JsonPath.read(DOCUMENT, "$.characters[?(@.name == 'Luke Skywalker' && @.occupation == 'Farm boy')]"); + + assertEquals("[{\"occupation\":\"Farm boy\",\"name\":\"Luke Skywalker\",\"aliases\":[\"Nerf herder\"],\"offspring\":null}]", o.toString()); + } + + @Test + public void not_equal_in_and_operator_filter() { + + + Object o = JsonPath.read(DOCUMENT, "$.characters[?(@.name == 'Luke Skywalker' && @.occupation != 'Farm boy')]"); + assertEquals("[]", o.toString()); + + o = JsonPath.read(DOCUMENT, "$.characters[?(@.name == 'Luke Skywalker' && @.occupation != 'City boy')]"); + assertEquals("[{\"occupation\":\"Farm boy\",\"name\":\"Luke Skywalker\",\"aliases\":[\"Nerf herder\"],\"offspring\":null}]", o.toString()); + + + } @Test public void nulls_filter() { diff --git a/json-path/src/test/java/com/jayway/jsonpath/HttpProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/HttpProviderTest.java index cd1d5417..dac8704d 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/HttpProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/HttpProviderTest.java @@ -17,19 +17,19 @@ import static junit.framework.Assert.assertEquals; * Date: 3/10/12 * Time: 8:12 AM */ -@Ignore +//@Ignore public class HttpProviderTest { private static final String EXPECTED = "{\n" + " \"results\" : [],\n" + - " \"status\" : \"REQUEST_DENIED\"\n" + + " \"status\" : \"ZERO_RESULTS\"\n" + "}"; @Test public void http_get() throws Exception { - URL url = new URL("http://maps.googleapis.com/maps/api/geocode/json"); + URL url = new URL("http://maps.googleapis.com/maps/api/geocode/json?sensor=false"); InputStream inputStream = null; try { diff --git a/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java b/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java index b77e15c1..f30a90ea 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java @@ -28,7 +28,6 @@ public class IssuesTest { @Test public void issue_36() { - String json = "{\n" + "\n" + " \"arrayOfObjectsAndArrays\" : [ { \"k\" : [\"json\"] }, { \"k\":[\"path\"] }, { \"k\" : [\"is\"] }, { \"k\" : [\"cool\"] } ],\n" + @@ -42,8 +41,6 @@ public class IssuesTest { assertEquals("[[\"json\"],[\"path\"],[\"is\"],[\"cool\"]]", o1.toString()); assertEquals("[\"json\",\"path\",\"is\",\"cool\"]", o2.toString()); - - } @Test(expected = PathNotFoundException.class) diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilterTest.java index 3e04028d..bab0fb97 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/filter/ArrayEvalFilterTest.java @@ -3,6 +3,8 @@ package com.jayway.jsonpath.internal.filter; import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * User: kalle @@ -11,33 +13,44 @@ import static org.junit.Assert.assertEquals; */ public class ArrayEvalFilterTest { + @Test + public void can_determine_condition_statement() { + + assertTrue(ArrayEvalFilter.isConditionStatement("[?(@.id == 5 && @.name == 'kalle')]")); + assertTrue(ArrayEvalFilter.isConditionStatement("[?( @==5)]")); + assertTrue(ArrayEvalFilter.isConditionStatement("[?(@.id == 5)]")); + + + + } + @Test public void condition_statements_can_be_parsed() { //assertEquals(new ArrayEvalFilter.ConditionStatement("@.length", ">", "0"), ArrayEvalFilter.createConditionStatement("[?(@.length>0)]")); //int array - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("[?(@==5)]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("[?(@ == 5)]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("[ ?(@ == 5) ]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("[ ?( @ == 5) ]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("[ ?( @ == 5 ) ]")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("@==5")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("@ == 5")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement(" @ == 5 ")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("@ ==5")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "5"), ArrayEvalFilter.createConditionStatement("@== 5 ")); //String array - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "one"), ArrayEvalFilter.createConditionStatement("[?(@=='one')]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "one monkey"), ArrayEvalFilter.createConditionStatement("[?(@ == 'one monkey')]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "two"), ArrayEvalFilter.createConditionStatement("[?(@ == 'two')]")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "one"), ArrayEvalFilter.createConditionStatement("@=='one'")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "one monkey"), ArrayEvalFilter.createConditionStatement("@ == 'one monkey' ")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@", "==", "two"), ArrayEvalFilter.createConditionStatement("@ == 'two'")); //Sub item dot notation - assertEquals(new ArrayEvalFilter.ConditionStatement("@.name", "==", "true"), ArrayEvalFilter.createConditionStatement("[?(@.name == true)]")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@.name", "==", "true"), ArrayEvalFilter.createConditionStatement("@.name == true")); //Sub item bracket notation - assertEquals(new ArrayEvalFilter.ConditionStatement("@['name']", "==", "true"), ArrayEvalFilter.createConditionStatement("[?(@['name'] == true)]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@.['name']", "==", "true"), ArrayEvalFilter.createConditionStatement("[?(@.['name'] == true)]")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@['name']", "==", "true"), ArrayEvalFilter.createConditionStatement("@['name'] == true")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@.['name']", "==", "true"), ArrayEvalFilter.createConditionStatement("@.['name'] == true")); //Sub path notation - assertEquals(new ArrayEvalFilter.ConditionStatement("@['name']['age']", "!=", "true"), ArrayEvalFilter.createConditionStatement("[?(@['name']['age'] != true)]")); - assertEquals(new ArrayEvalFilter.ConditionStatement("@.['name'].age", ">", "true"), ArrayEvalFilter.createConditionStatement("[?(@.['name'].age > true)]")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@['name']['age']", "!=", "true"), ArrayEvalFilter.createConditionStatement("@['name']['age'] != true")); + assertEquals(new ArrayEvalFilter.ConditionStatement("@.['name'].age", ">", "true"), ArrayEvalFilter.createConditionStatement("@.['name'].age > true")); }