From d77e302cb30664eeb67c5700b495c41b17a63116 Mon Sep 17 00:00:00 2001 From: kalle Date: Mon, 7 Feb 2011 08:50:20 +0100 Subject: [PATCH] improvements --- README | 6 +- .../java/com/jayway/jsonpath/JsonPath.java | 2 +- ...pression.java => ExpressionEvaluator.java} | 26 ++++---- .../jsonpath/filter/JsonPathFilterChain.java | 5 +- .../jayway/jsonpath/filter/ListFilter.java | 42 ++++++++----- .../jayway/jsonpath/ExpressionEvalTest.java | 58 +++++++++--------- .../com/jayway/jsonpath/JsonPathTest.java | 31 ++++++++-- jsonpath.png | Bin 0 -> 4136 bytes 8 files changed, 107 insertions(+), 63 deletions(-) rename json-path/src/main/java/com/jayway/jsonpath/eval/{Expression.java => ExpressionEvaluator.java} (78%) create mode 100644 jsonpath.png diff --git a/README b/README index 7870c033..f7853d9b 100644 --- a/README +++ b/README @@ -1 +1,5 @@ -Java DSL for reading and testing JSON documents. \ No newline at end of file +Java DSL for reading and testing JSON documents. + + + +Santa Fe LET 50 \ No newline at end of file diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java index 002dd787..eaf604d3 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -168,7 +168,7 @@ public class JsonPath { if (log.isLoggable(Level.WARNING)) { if (!PathUtil.isPathDefinite(jsonPath)) { - log.warning("Using readOne(...) on a not definite json path may give incorrect results."); + log.warning("Using readOne() on a not definite json path may give incorrect results. Path : " + jsonPath); } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/eval/Expression.java b/json-path/src/main/java/com/jayway/jsonpath/eval/ExpressionEvaluator.java similarity index 78% rename from json-path/src/main/java/com/jayway/jsonpath/eval/Expression.java rename to json-path/src/main/java/com/jayway/jsonpath/eval/ExpressionEvaluator.java index 1081896e..8da729f1 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/eval/Expression.java +++ b/json-path/src/main/java/com/jayway/jsonpath/eval/ExpressionEvaluator.java @@ -5,7 +5,7 @@ package com.jayway.jsonpath.eval; * Date: 2/4/11 * Time: 9:21 PM */ -public class Expression { +public class ExpressionEvaluator { public static boolean eval(T actual, String comparator, String expected) { @@ -35,17 +35,17 @@ public class Expression { Integer e = Integer.parseInt(expected.trim()); if ("=".equals(comparator)) { - return a.longValue() == e.longValue(); + return a.intValue() == e.intValue(); } else if ("!=".equals(comparator) || "<>".equals(comparator)) { - return a.longValue() != e.longValue(); + return a.intValue() != e.intValue(); } else if (">".equals(comparator)) { - return a.longValue() > e.longValue(); + return a.intValue() > e.intValue(); } else if (">=".equals(comparator)) { - return a.longValue() >= e.longValue(); + return a.intValue() >= e.intValue(); } else if ("<".equals(comparator)) { - return a.longValue() < e.longValue(); + return a.intValue() < e.intValue(); } else if ("<=".equals(comparator)) { - return a.longValue() <= e.longValue(); + return a.intValue() <= e.intValue(); } } else if (actual instanceof Double) { @@ -53,17 +53,17 @@ public class Expression { Double e = Double.parseDouble(expected.trim()); if ("=".equals(comparator)) { - return a.longValue() == e.longValue(); + return a.doubleValue() == e.doubleValue(); } else if ("!=".equals(comparator) || "<>".equals(comparator)) { - return a.longValue() != e.longValue(); + return a.doubleValue() != e.doubleValue(); } else if (">".equals(comparator)) { - return a.longValue() > e.longValue(); + return a.doubleValue() > e.doubleValue(); } else if (">=".equals(comparator)) { - return a.longValue() >= e.longValue(); + return a.doubleValue() >= e.doubleValue(); } else if ("<".equals(comparator)) { - return a.longValue() < e.longValue(); + return a.doubleValue() < e.doubleValue(); } else if ("<=".equals(comparator)) { - return a.longValue() <= e.longValue(); + return a.doubleValue() <= e.doubleValue(); } } else if (actual instanceof String) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterChain.java b/json-path/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterChain.java index c6996c29..c18d78a2 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterChain.java +++ b/json-path/src/main/java/com/jayway/jsonpath/filter/JsonPathFilterChain.java @@ -1,8 +1,8 @@ package com.jayway.jsonpath.filter; +import com.jayway.jsonpath.InvalidPathException; import org.json.simple.JSONArray; -import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -37,6 +37,9 @@ public class JsonPathFilterChain { List result = rootList; for (JsonPathFilterBase filter : filters) { + if (filter == null) { + throw new InvalidPathException(); + } result = filter.apply(result); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/filter/ListFilter.java b/json-path/src/main/java/com/jayway/jsonpath/filter/ListFilter.java index b44acc1a..0110e911 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/filter/ListFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/filter/ListFilter.java @@ -1,7 +1,7 @@ package com.jayway.jsonpath.filter; import com.jayway.jsonpath.JsonUtil; -import com.jayway.jsonpath.eval.Expression; +import com.jayway.jsonpath.eval.ExpressionEvaluator; import org.json.simple.JSONArray; //import javax.script.ScriptEngine; @@ -13,8 +13,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * Created by IntelliJ IDEA. - * User: kallestenflo + * User: kalle stenflo * Date: 2/2/11 * Time: 2:32 PM */ @@ -22,14 +21,14 @@ public class ListFilter extends JsonPathFilterBase { //private static ScriptEngine SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("js"); - private static final Pattern LIST_INDEX_PATTERN = Pattern.compile("\\[(\\s?\\d+\\s?,?)+\\]"); //[1] OR [1,2,3] - private static final Pattern LIST_PULL_PATTERN = Pattern.compile("\\[\\s?:(\\d+)\\s?\\]"); //[ :2 ] - private static final Pattern LIST_WILDCARD_PATTERN = Pattern.compile("\\[\\*\\]"); + private static final Pattern LIST_INDEX_PATTERN = Pattern.compile("\\[(\\s?\\d+\\s?,?)+\\]"); //[1] OR [1,2,3] + private static final Pattern LIST_PULL_PATTERN = Pattern.compile("\\[\\s?:(\\d+)\\s?\\]"); //[ :2 ] + private static final Pattern LIST_WILDCARD_PATTERN = Pattern.compile("\\[\\*\\]"); //[*] private static final Pattern LIST_TAIL_PATTERN_SHORT = Pattern.compile("\\[\\s*-\\s*(\\d+):\\s*\\]"); // [(@.length - 12)] OR [-13:] - private static final Pattern LIST_TAIL_PATTERN_LONG = Pattern.compile("\\[\\s*\\(\\s*@\\.length\\s*-\\s*(\\d+)\\s*\\)\\s*\\]"); + private static final Pattern LIST_TAIL_PATTERN_LONG = Pattern.compile("\\[\\s*\\(\\s*@\\.length\\s*-\\s*(\\d+)\\s*\\)\\s*\\]"); //[(@.length-1)] private static final Pattern LIST_TAIL_PATTERN = Pattern.compile("(" + LIST_TAIL_PATTERN_SHORT.pattern() + "|" + LIST_TAIL_PATTERN_LONG.pattern() + ")"); - private static final Pattern LIST_ITEM_HAS_PROPERTY_PATTERN = Pattern.compile("\\[\\s?\\?\\s?\\(\\s?@\\.(\\w+)\\s?\\)\\s?\\]"); - private static final Pattern LIST_ITEM_MATCHES_EVAL = Pattern.compile("\\[\\s?\\?\\s?\\(\\s?@.(\\w+)\\s?([=<>]+)\\s?(.*)\\s?\\)\\s?\\]"); //[ ?( @.title< 'ko' ) ] + private static final Pattern LIST_ITEM_HAS_PROPERTY_PATTERN = Pattern.compile("\\[\\s?\\?\\s?\\(\\s?@\\.(\\w+)\\s?\\)\\s?\\]"); //[?(@.title)] + private static final Pattern LIST_ITEM_MATCHES_EVAL = Pattern.compile("\\[\\s?\\?\\s?\\(\\s?@.(\\w+)\\s?([=<>]+)\\s?(.*)\\s?\\)\\s?\\]"); //[?( @.title< 'ko')] private final String pathFragment; @@ -106,6 +105,7 @@ public class ListFilter extends JsonPathFilterBase { for (Object current : items) { List array = JsonUtil.toList(current); + result.add(array.get(getTailIndex(array.size()))); } return result; @@ -115,10 +115,12 @@ public class ListFilter extends JsonPathFilterBase { List result = new JSONArray(); for (Object current : items) { + List target = JsonUtil.toList(current); Integer[] index = getArrayIndex(); for (int i : index) { - - result.add(JsonUtil.toList(current).get(i)); + if(indexIsInRange(target, i)){ + result.add(target.get(i)); + } } } return result; @@ -128,10 +130,12 @@ public class ListFilter extends JsonPathFilterBase { List result = new JSONArray(); for (Object current : items) { + List target = JsonUtil.toList(current); Integer[] index = getListPullIndex(); for (int i : index) { - - result.add(JsonUtil.toList(current).get(i)); + if(indexIsInRange(target, i)){ + result.add(target.get(i)); + } } } return result; @@ -164,7 +168,7 @@ public class ListFilter extends JsonPathFilterBase { System.out.println("EVAL" + expression); - return Expression.eval(propertyValue, operator, expected); + return ExpressionEvaluator.eval(propertyValue, operator, expected); } return false; @@ -230,4 +234,14 @@ public class ListFilter extends JsonPathFilterBase { return index.toArray(new Integer[0]); } + private boolean indexIsInRange(List list, int index){ + if(index < 0){ + return false; + }else if(index > list.size() -1){ + return false; + }else { + return true; + } + } + } \ No newline at end of file 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 bb9ca807..d71c50ac 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java @@ -1,6 +1,6 @@ package com.jayway.jsonpath; -import com.jayway.jsonpath.eval.Expression; +import com.jayway.jsonpath.eval.ExpressionEvaluator; import org.junit.Test; import static org.junit.Assert.assertFalse; @@ -18,46 +18,46 @@ public class ExpressionEvalTest { @Test public void long_eval() throws Exception { - assertTrue(Expression.eval(1L, "=", "1")); - assertTrue(Expression.eval(2L, "!=", "1")); - assertTrue(Expression.eval(2L, ">", "1")); - assertTrue(Expression.eval(2L, ">=", "1")); - assertTrue(Expression.eval(2L, ">=", "2")); - assertTrue(Expression.eval(1L, "<", "2")); - assertTrue(Expression.eval(2L, "<=", "2")); + assertTrue(ExpressionEvaluator.eval(1L, "=", "1")); + assertTrue(ExpressionEvaluator.eval(2L, "!=", "1")); + assertTrue(ExpressionEvaluator.eval(2L, ">", "1")); + assertTrue(ExpressionEvaluator.eval(2L, ">=", "1")); + assertTrue(ExpressionEvaluator.eval(2L, ">=", "2")); + assertTrue(ExpressionEvaluator.eval(1L, "<", "2")); + assertTrue(ExpressionEvaluator.eval(2L, "<=", "2")); - assertFalse(Expression.eval(1, ">", "2")); - assertFalse(Expression.eval(1, ">=", "2")); - assertFalse(Expression.eval(2, "<", "1")); - assertFalse(Expression.eval(2, "<=", "1")); - assertFalse(Expression.eval(1, "=", "2")); - assertFalse(Expression.eval(1, "!=", "1")); + assertFalse(ExpressionEvaluator.eval(1, ">", "2")); + assertFalse(ExpressionEvaluator.eval(1, ">=", "2")); + assertFalse(ExpressionEvaluator.eval(2, "<", "1")); + assertFalse(ExpressionEvaluator.eval(2, "<=", "1")); + assertFalse(ExpressionEvaluator.eval(1, "=", "2")); + assertFalse(ExpressionEvaluator.eval(1, "!=", "1")); } @Test public void double_eval() throws Exception { - assertTrue(Expression.eval(1D, "=", "1")); - assertTrue(Expression.eval(2D, "!=", "1")); - assertTrue(Expression.eval(2D, ">", "1")); - assertTrue(Expression.eval(2D, ">=", "1")); - assertTrue(Expression.eval(2D, ">=", "2")); - assertTrue(Expression.eval(1D, "<", "2")); - assertTrue(Expression.eval(2D, "<=", "2")); + assertTrue(ExpressionEvaluator.eval(1D, "=", "1")); + assertTrue(ExpressionEvaluator.eval(2D, "!=", "1")); + assertTrue(ExpressionEvaluator.eval(2D, ">", "1")); + assertTrue(ExpressionEvaluator.eval(2D, ">=", "1")); + assertTrue(ExpressionEvaluator.eval(2D, ">=", "2")); + assertTrue(ExpressionEvaluator.eval(1D, "<", "2")); + assertTrue(ExpressionEvaluator.eval(2D, "<=", "2")); - assertFalse(Expression.eval(1D, ">", "2")); - assertFalse(Expression.eval(1D, ">=", "2")); - assertFalse(Expression.eval(2D, "<", "1")); - assertFalse(Expression.eval(2D, "<=", "1")); - assertFalse(Expression.eval(1D, "=", "2")); - assertFalse(Expression.eval(1D, "!=", "1")); + assertFalse(ExpressionEvaluator.eval(1D, ">", "2")); + assertFalse(ExpressionEvaluator.eval(1D, ">=", "2")); + assertFalse(ExpressionEvaluator.eval(2D, "<", "1")); + assertFalse(ExpressionEvaluator.eval(2D, "<=", "1")); + assertFalse(ExpressionEvaluator.eval(1D, "=", "2")); + assertFalse(ExpressionEvaluator.eval(1D, "!=", "1")); } @Test public void string_eval() throws Exception { - assertTrue(Expression.eval("A", "=", "A")); - assertTrue(Expression.eval("B", "!=", "A")); + assertTrue(ExpressionEvaluator.eval("A", "=", "A")); + assertTrue(ExpressionEvaluator.eval("B", "!=", "A")); } diff --git a/json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java b/json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java index 5cd5b17b..e713d031 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java @@ -7,7 +7,6 @@ import java.util.List; import java.util.Map; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasItems; import static org.junit.Assert.*; @@ -57,7 +56,7 @@ public class JsonPathTest { List list = JsonPath.read(DOCUMENT, "$.store"); - assertEquals(2, ((Map)list.get(0)).values().size()); + assertEquals(2, ((Map) list.get(0)).values().size()); } @@ -68,7 +67,7 @@ public class JsonPathTest { JsonPath path = JsonPath.compile("$.store.book[1]"); - List list = path.read(DOCUMENT); + List list = path.read(DOCUMENT); System.out.println(list.toString()); @@ -124,6 +123,7 @@ public class JsonPathTest { assertThat(JsonPath.read(DOCUMENT, "$.store.book[0,1].author"), hasItems("Nigel Rees", "Evelyn Waugh")); assertTrue(JsonPath.read(DOCUMENT, "$.store.book[0,1].author").size() == 2); } + @Test public void read_store_book_pull_first_2() throws Exception { @@ -146,7 +146,7 @@ public class JsonPathTest { } - @Test + @Test public void all_books_with_category_reference() throws Exception { assertThat(JsonPath.read(DOCUMENT, "$..book[?(@.category = 'reference')].title"), hasItems("Sayings of the Century")); @@ -162,4 +162,27 @@ public class JsonPathTest { System.out.println(all.toString()); } + + @Test + public void access_index_out_of_bounds_does_not_throw_exception() throws Exception { + + List res = JsonPath.read(DOCUMENT, "$.store.book[100].author"); + + assertTrue(res.isEmpty()); + + res = JsonPath.read(DOCUMENT, "$.store.book[100, 200].author"); + + assertTrue(res.isEmpty()); + } + + + @Test(expected = InvalidPathException.class) + public void invalid_space_path_throws_exception() throws Exception { + JsonPath.read(DOCUMENT, "space is not good"); + } + + @Test(expected = InvalidPathException.class) + public void invalid_new_path_throws_exception() throws Exception { + JsonPath.read(DOCUMENT, "new "); + } } diff --git a/jsonpath.png b/jsonpath.png new file mode 100644 index 0000000000000000000000000000000000000000..f760889ffbd26da8eaf8073a94935504a80b2a75 GIT binary patch literal 4136 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