From c3d60b764d1d3adf1bb6e00870f90ef09f80ee74 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Wed, 29 Feb 2012 10:43:35 +0100 Subject: [PATCH] Fixed JsonPath compliance issue. see http://code.google.com/p/json-path/issues/detail?id=7 --- .../java/com/jayway/jsonpath/JsonPath.java | 11 +- .../com/jayway/jsonpath/reader/PathToken.java | 5 + .../reader/filter/ArrayEvalFilter.java | 5 + .../reader/filter/ArrayIndexFilter.java | 5 + .../jsonpath/reader/filter/FieldFilter.java | 38 ++++ .../jayway/jsonpath/reader/filter/Filter.java | 8 + .../jsonpath/reader/filter/FilterFactory.java | 4 +- .../reader/filter/HasFieldFilter.java | 5 + .../reader/filter/PassThrewFilter.java | 10 +- .../jsonpath/reader/filter/ScanFilter.java | 5 + .../reader/filter/WildcardFilter.java | 5 + .../test/java/com/jayway/jsonpath/Issues.java | 27 +++ .../com/jayway/jsonpath/JsonPathTest.java | 3 +- .../jayway/jsonpath/PathTokenizerTest.java | 170 ------------------ 14 files changed, 126 insertions(+), 175 deletions(-) create mode 100644 json-path/src/test/java/com/jayway/jsonpath/Issues.java delete mode 100644 json-path/src/test/java/com/jayway/jsonpath/PathTokenizerTest.java 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 acda6937..d600f384 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -3,6 +3,7 @@ package com.jayway.jsonpath; import com.jayway.jsonpath.reader.PathToken; import com.jayway.jsonpath.reader.PathTokenizer; +import com.jayway.jsonpath.reader.filter.Filter; import com.jayway.jsonpath.spi.JsonProvider; import java.util.List; @@ -149,8 +150,16 @@ public class JsonPath { Object result = container; + boolean inArrayContext = false; + for (PathToken pathToken : tokenizer) { - result = pathToken.filter(result, jsonProvider); + Filter filter = pathToken.getFilter(); + result = filter.filter(result, jsonProvider, inArrayContext); + + if (!inArrayContext) { + inArrayContext = filter.isArrayFilter(); + } + //result = pathToken.filter(result, jsonProvider); } return (T) result; } diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/PathToken.java b/json-path/src/main/java/com/jayway/jsonpath/reader/PathToken.java index 78a44b7b..cdacd552 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/PathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/PathToken.java @@ -1,5 +1,6 @@ package com.jayway.jsonpath.reader; +import com.jayway.jsonpath.reader.filter.Filter; import com.jayway.jsonpath.reader.filter.FilterFactory; import com.jayway.jsonpath.spi.JsonProvider; @@ -17,6 +18,10 @@ public class PathToken { this.fragment = fragment; } + public Filter getFilter(){ + return FilterFactory.createFilter(fragment); + } + public Object filter(Object model, JsonProvider jsonProvider){ return FilterFactory.createFilter(fragment).filter(model, jsonProvider); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayEvalFilter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayEvalFilter.java index 0457d4e7..39ce8ea7 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayEvalFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayEvalFilter.java @@ -48,6 +48,11 @@ public class ArrayEvalFilter extends Filter { return result; } + @Override + public boolean isArrayFilter() { + return true; + } + private boolean isMatch(Object check, ConditionStatement conditionStatement, JsonProvider jsonProvider) { if (!jsonProvider.isMap(check)) { return false; diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayIndexFilter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayIndexFilter.java index cb5d46ba..840a731a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayIndexFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ArrayIndexFilter.java @@ -58,4 +58,9 @@ public class ArrayIndexFilter extends Filter { } } } + + @Override + public boolean isArrayFilter() { + return true; + } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FieldFilter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FieldFilter.java index 82f08c35..82f940c3 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FieldFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FieldFilter.java @@ -17,8 +17,38 @@ public class FieldFilter extends Filter { super(condition); } + @Override + public Object filter(Object obj, JsonProvider jsonProvider, boolean inArrayContext) { + if (jsonProvider.isList(obj)) { + if (!inArrayContext) { + return null; + } else { + List result = jsonProvider.createList(); + for (Object current : jsonProvider.toList(obj)) { + if (jsonProvider.isMap(current)) { + Map map = jsonProvider.toMap(current); + if (map.containsKey(condition)) { + Object o = map.get(condition); + if (jsonProvider.isList(o)) { + result.addAll(jsonProvider.toList(o)); + } else { + result.add(map.get(condition)); + } + } + } + } + return result; + } + } else { + return jsonProvider.getMapValue(obj, condition); + } + } + + public Object filter(Object obj, JsonProvider jsonProvider) { if (jsonProvider.isList(obj)) { + return obj; + /* List result = jsonProvider.createList(); for (Object current : jsonProvider.toList(obj)) { if (jsonProvider.isMap(current)) { @@ -34,8 +64,16 @@ public class FieldFilter extends Filter { } } return result; + */ } else { return jsonProvider.getMapValue(obj, condition); } } + + @Override + public boolean isArrayFilter() { + return false; + } + + } diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/Filter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/Filter.java index c6746a77..72bbf99e 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/Filter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/Filter.java @@ -29,6 +29,14 @@ public abstract class Filter { return res; } + public Object filter(Object obj, JsonProvider jsonProvider, boolean inArrayContext){ + return filter(obj, jsonProvider); + } + public abstract Object filter(Object obj, JsonProvider jsonProvider); + + + public abstract boolean isArrayFilter(); + } diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FilterFactory.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FilterFactory.java index 020a5d50..c9e425fd 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FilterFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/FilterFactory.java @@ -8,8 +8,8 @@ package com.jayway.jsonpath.reader.filter; */ public class FilterFactory { - private final static Filter DOCUMENT_FILTER = new PassThrewFilter("$"); - private final static Filter ALL_ARRAY_ITEMS_FILTER = new PassThrewFilter("[*]"); + private final static Filter DOCUMENT_FILTER = new PassThrewFilter("$", false); + private final static Filter ALL_ARRAY_ITEMS_FILTER = new PassThrewFilter("[*]", true); private final static Filter WILDCARD_FILTER = new WildcardFilter("*"); private final static Filter SCAN_FILTER = new ScanFilter(".."); diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/HasFieldFilter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/HasFieldFilter.java index 627612ec..52e448f8 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/HasFieldFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/HasFieldFilter.java @@ -43,4 +43,9 @@ public class HasFieldFilter extends Filter { } return result; } + + @Override + public boolean isArrayFilter() { + return true; + } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/PassThrewFilter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/PassThrewFilter.java index 00c90a7f..9dc5782d 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/PassThrewFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/PassThrewFilter.java @@ -10,11 +10,19 @@ import com.jayway.jsonpath.spi.JsonProvider; */ public class PassThrewFilter extends Filter { - public PassThrewFilter(String condition) { + private boolean isArrayFilter; + + public PassThrewFilter(String condition, boolean isArrayFilter) { super(condition); + this.isArrayFilter = isArrayFilter; } public Object filter(Object obj, JsonProvider jsonProvider) { return obj; } + + @Override + public boolean isArrayFilter() { + return isArrayFilter; + } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ScanFilter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ScanFilter.java index 609e2da2..49ae50ea 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ScanFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/ScanFilter.java @@ -25,6 +25,11 @@ public class ScanFilter extends Filter { return result; } + @Override + public boolean isArrayFilter() { + return true; + } + private void scan(Object container, List result, JsonProvider jsonProvider) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/WildcardFilter.java b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/WildcardFilter.java index f3976910..04177710 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/reader/filter/WildcardFilter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/reader/filter/WildcardFilter.java @@ -33,4 +33,9 @@ public class WildcardFilter extends Filter { } return result; } + + @Override + public boolean isArrayFilter() { + return true; + } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/Issues.java b/json-path/src/test/java/com/jayway/jsonpath/Issues.java new file mode 100644 index 00000000..f2415b2b --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/Issues.java @@ -0,0 +1,27 @@ +package com.jayway.jsonpath; + +import org.junit.Test; + +import static junit.framework.Assert.assertNull; + +/** + * Created by IntelliJ IDEA. + * User: kallestenflo + * Date: 2/29/12 + * Time: 8:42 AM + */ +public class Issues { + @Test + public void issue_7() throws Exception { + + String json = "{ \"foo\" : [\n" + + " { \"id\": 1 }, \n" + + " { \"id\": 2 }, \n" + + " { \"id\": 3 }\n" + + " ] }"; + + + assertNull(JsonPath.read(json, "$.foo.id")); + } + +} 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 db9a3ac9..5ba9847d 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java @@ -77,7 +77,8 @@ public class JsonPathTest { @Test public void array_start_expands() throws Exception { - assertThat(JsonPath.>read(ARRAY_EXPAND, "$[?(@.parent = 'ONE')].child.name"), hasItems("NAME_ONE")); + //assertThat(JsonPath.>read(ARRAY_EXPAND, "$[?(@.parent = 'ONE')].child.name"), hasItems("NAME_ONE")); + assertThat(JsonPath.>read(ARRAY_EXPAND, "$[?(@['parent'] = 'ONE')].child.name"), hasItems("NAME_ONE")); } @Test diff --git a/json-path/src/test/java/com/jayway/jsonpath/PathTokenizerTest.java b/json-path/src/test/java/com/jayway/jsonpath/PathTokenizerTest.java deleted file mode 100644 index 413ee7f0..00000000 --- a/json-path/src/test/java/com/jayway/jsonpath/PathTokenizerTest.java +++ /dev/null @@ -1,170 +0,0 @@ -package com.jayway.jsonpath; - -import com.jayway.jsonpath.reader.PathToken; -import com.jayway.jsonpath.reader.PathTokenizer; -import com.jayway.jsonpath.spi.JsonProvider; -import org.junit.Test; - -import java.util.List; - -import static junit.framework.Assert.assertEquals; -import static org.hamcrest.Matchers.hasItems; -import static org.junit.Assert.assertThat; - -/** - * Created by IntelliJ IDEA. - * User: kallestenflo - * Date: 11/4/11 - * Time: 10:44 PM - */ -public class PathTokenizerTest { - - private JsonProvider jsonProvider = JsonProvider.getInstance(); - - public final static String DOCUMENT = - "{ \"store\": {\n" + - " \"book\": [ \n" + - " { \"category\": \"reference\",\n" + - " \"author\": \"Nigel Rees\",\n" + - " \"title\": \"Sayings of the Century\",\n" + - " \"price\": 8.95\n" + - " },\n" + - " { \"category\": \"fiction\",\n" + - " \"author\": \"Evelyn Waugh\",\n" + - " \"title\": \"Sword of Honour\",\n" + - " \"price\": 12.99\n" + - " },\n" + - " { \"category\": \"fiction\",\n" + - " \"author\": \"Herman Melville\",\n" + - " \"title\": \"Moby Dick\",\n" + - " \"isbn\": \"0-553-21311-3\",\n" + - " \"price\": 8.99\n" + - " },\n" + - " { \"category\": \"fiction\",\n" + - " \"author\": \"J. R. R. Tolkien\",\n" + - " \"title\": \"The Lord of the Rings\",\n" + - " \"custom\": \"onely this\",\n" + - " \"isbn\": \"0-395-19395-8\",\n" + - " \"price\": 22.99\n" + - " }\n" + - " ],\n" + - " \"bicycle\": {\n" + - " \"color\": \"red\",\n" + - " \"price\": 19.95,\n" + - " \"foo:bar\": \"fooBar\",\n" + - " \"dot.notation\": \"new\"\n" + - " }\n" + - " }\n" + - "}"; - - @Test - public void path_tokens_can_be_read() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.bicycle.color", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - - assertEquals("red", result); - } - - @Test - public void read_an_array_without_filters() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - - assertEquals(4, toList(result).size()); - } - - @Test - public void read_a_literal_property_from_object_in_array() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book[*].title", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - - assertEquals(4, toList(result).size()); - } - - @Test - public void read_a_literal_property_from_position_in_array() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book[0].title", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - - assertEquals("Sayings of the Century", result); - } - - @Test - public void read_a_literal_property_from_two_positions_in_array() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book[0, 1].author", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - - assertThat(this.toList(result), hasItems("Nigel Rees", "Evelyn Waugh")); - } - - @Test - public void read_a_literal_property_from_head_in_array() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book[:2].author", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - - assertThat(this.toList(result), hasItems("Nigel Rees", "Evelyn Waugh")); - } - - @Test - public void read_a_literal_property_from_tail_in_array() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book[-1:].author", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - assertEquals("J. R. R. Tolkien", result); - } - - @Test - public void field_defined_in_array_object() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book[?(@.custom)].author", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - assertThat(this.toList(result), hasItems("J. R. R. Tolkien")); - } - - @Test - public void property_value_in_array_object() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$.store.book[?(@.custom = 'onely this')].author", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - assertThat(this.toList(result), hasItems("J. R. R. Tolkien")); - } - - @Test - public void deep_scan() throws Exception { - Object result = jsonProvider.parse(DOCUMENT); - - for (PathToken pathToken : new PathTokenizer("$..author", jsonProvider)) { - result = pathToken.filter(result, jsonProvider); - } - assertThat(this.toList(result), hasItems("Nigel Rees","Evelyn Waugh", "J. R. R. Tolkien")); - } - - private List toList(Object obj) { - return (List) obj; - } - -}