diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java index e7ee007d..6b886029 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java @@ -111,20 +111,19 @@ public class PathCompiler { readWildCardToken(appender) || readFilterToken(appender) || readPlaceholderToken(appender) || - fail("Could not parse bracket statement at position " + path.position()); + fail("Could not parse token starting at position " + path.position() + ". Expected ?, ', 0-9, * "); case PERIOD: - return readDotSeparatorToken(appender) || - readScanToken(appender) || - fail("Could not parse token at position " + path.position()); + return readDotToken(appender) || + fail("Could not parse token starting at position " + path.position()); case WILDCARD: return readWildCardToken(appender) || - fail("Could not parse token at position " + path.position()); + fail("Could not parse token starting at position " + path.position()); case FUNCTION: return readFunctionToken(appender) || - fail("Could not parse token at position " + path.position()); + fail("Could not parse token starting at position " + path.position()); default: return readPropertyToken(appender) || - fail("Could not parse token at position " + path.position()); + fail("Could not parse token starting at position " + path.position()); } } @@ -156,21 +155,20 @@ public class PathCompiler { } // - // . + // . and .. // - private boolean readDotSeparatorToken(PathTokenAppender appender) { - if (!path.currentCharIs('.') || path.nextCharIs('.')) { - return false; - } - if (!path.hasMoreCharacters()) { + private boolean readDotToken(PathTokenAppender appender) { + if (path.currentCharIs('.') && path.nextCharIs('.')) { + appender.appendPathToken(PathTokenFactory.crateScanToken()); + path.incrementPosition(2); + } else if (!path.hasMoreCharacters()) { throw new InvalidPathException("Path must not end with a '."); + } else { + path.incrementPosition(1); + } + if(path.currentCharIs('.')){ + throw new InvalidPathException("Character '.' on position " + path.position() + " is not valid."); } -// if (path.nextSignificantCharIs('[')) { -// throw new InvalidPathException("A bracket may not follow a '."); -// } - - path.incrementPosition(1); - return readNextToken(appender); } @@ -417,20 +415,6 @@ public class PathCompiler { return path.currentIsTail() || readNextToken(appender); } - // - // .. - // - private boolean readScanToken(PathTokenAppender appender) { - if (!path.currentCharIs(PERIOD) || !path.nextCharIs(PERIOD)) { - return false; - } - appender.appendPathToken(PathTokenFactory.crateScanToken()); - path.incrementPosition(2); - - return readNextToken(appender); - } - - public static boolean fail(String message) { throw new InvalidPathException(message); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/token/ArrayPathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/token/ArrayPathToken.java index 65c7784d..8236bc9d 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/token/ArrayPathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/token/ArrayPathToken.java @@ -181,7 +181,7 @@ public class ArrayPathToken extends PathToken { if (! isUpstreamDefinite()) { return false; } else { - throw new InvalidPathException(format("Filter: %s can only be applied to arrays. Current context is: %s", toString(), model)); + throw new PathNotFoundException(format("Filter: %s can only be applied to arrays. Current context is: %s", toString(), model)); } } return true; diff --git a/json-path/src/test/java/com/jayway/jsonpath/DeepScanTest.java b/json-path/src/test/java/com/jayway/jsonpath/DeepScanTest.java index faccd840..f8c72fe2 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/DeepScanTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/DeepScanTest.java @@ -47,8 +47,8 @@ public class DeepScanTest extends BaseTest { assertEvaluationThrows("{\"foo\": {\"bar\": null}}", "$.foo.bar.[5]", PathNotFoundException.class); assertEvaluationThrows("{\"foo\": {\"bar\": null}}", "$.foo.bar.[5, 10]", PathNotFoundException.class); - assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$.foo.bar.[5]", InvalidPathException.class); - assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$.foo.bar.[5, 10]", InvalidPathException.class); + assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$.foo.bar.[5]", PathNotFoundException.class); + assertEvaluationThrows("{\"foo\": {\"bar\": 4}}", "$.foo.bar.[5, 10]", PathNotFoundException.class); assertEvaluationThrows("{\"foo\": {\"bar\": []}}", "$.foo.bar.[5]", PathNotFoundException.class); } diff --git a/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java index a0a9f79c..d24e30d1 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java @@ -4,7 +4,11 @@ import org.json.JSONArray; import org.json.JSONObject; import org.junit.Test; +import java.util.List; +import java.util.Map; + import static com.jayway.jsonpath.JsonPath.using; +import static org.assertj.core.api.Assertions.assertThat; public class JsonOrgJsonProviderTest extends BaseTest { @@ -14,7 +18,7 @@ public class JsonOrgJsonProviderTest extends BaseTest { JSONObject book = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0]"); - System.out.println(book); + assertThat(book.get("author").toString()).isEqualTo("Nigel Rees"); } @Test @@ -22,7 +26,7 @@ public class JsonOrgJsonProviderTest extends BaseTest { String category = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[0].category"); - System.out.println(category); + assertThat(category).isEqualTo("reference"); } @Test @@ -30,14 +34,14 @@ public class JsonOrgJsonProviderTest extends BaseTest { JSONArray fictionBooks = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book[?(@.category == 'fiction')]"); - System.out.println(fictionBooks); + assertThat(fictionBooks.length()).isEqualTo(3); } @Test public void result_can_be_mapped_to_object() { - Object result = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book", Object.class); + List> books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$.store.book", List.class); - System.out.println(result); + assertThat(books.size()).isEqualTo(4); } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java b/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java index 9920a10c..8c5d67ae 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java +++ b/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java @@ -15,10 +15,10 @@ public final class TestUtils { /** * Shortcut for expected exception testing during path evaluation. * - * @param conf conf to use during evaluation * @param json json to parse * @param path jsonpath do evaluate * @param expected expected exception class (reference comparison, not an instanceof) + * @param conf conf to use during evaluation */ public static void assertEvaluationThrows(final String json, final String path, Class expected, final Configuration conf) { @@ -35,6 +35,7 @@ public final class TestUtils { * Assertion which requires empty list as a result of indefinite path search. * @param json json to be parsed * @param path path to be evaluated + * @param conf conf to use during evaluation */ public static void assertHasNoResults(final String json, final String path, Configuration conf) { assertHasResults(json, path, 0, conf); @@ -54,6 +55,7 @@ public final class TestUtils { * @param json json to be parsed * @param path path to be evaluated * @param expectedResultCount expected number of nodes to be found + * @param conf conf to use during evaluation */ public static void assertHasResults(final String json, final String path, final int expectedResultCount, Configuration conf) { Object result = JsonPath.using(conf).parse(json).read(path); diff --git a/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java b/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java index 23cc9026..fdcbc2d9 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java @@ -5,6 +5,7 @@ import com.jayway.jsonpath.BaseTest; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.Filter; +import com.jayway.jsonpath.InvalidPathException; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Option; import com.jayway.jsonpath.PathNotFoundException; @@ -42,6 +43,71 @@ public class IssuesTest extends BaseTest { private static final JsonProvider jp = Configuration.defaultConfiguration().jsonProvider(); + @Test + public void issue_114_a() { + String json = "{ \"p\":{\n" + + "\"s\": { \"u\": \"su\" }, \n" + + "\"t\": { \"u\": \"tu\" }\n" + + "}}"; + + List result = read(json, "$.p.['s', 't'].u"); + assertThat(result).containsExactly("su","tu"); + } + + @Test + public void issue_114_b() { + String json = "{ \"p\": [\"valp\", \"valq\", \"valr\"] }"; + + List result = read(json, "$.p[?(@ == 'valp')]"); + assertThat(result).containsExactly("valp"); + } + + @Test + public void issue_114_c() { + String json = "{ \"p\": [\"valp\", \"valq\", \"valr\"] }"; + + List result = read(json, "$.p[?(@[0] == 'valp')]"); + assertThat(result).isEmpty(); + } + + @Test(expected = InvalidPathException.class) + public void issue_114_d() { + read(JSON_BOOK_DOCUMENT, "$..book[(@.length-1)] "); + } + + + @Test + public void issue_151() { + String json = "{\n" + + "\"datas\": {\n" + + " \"selling\": {\n" + + " \"3\": [\n" + + " 26452067,\n" + + " 31625950\n" + + " ],\n" + + " \"206\": [\n" + + " 32381852,\n" + + " 32489262\n" + + " ],\n" + + " \"208\": [\n" + + " 458\n" + + " ],\n" + + " \"217\": [\n" + + " 27364892\n" + + " ],\n" + + " \"226\": [\n" + + " 30474109\n" + + " ]\n" + + " }\n" + + "},\n" + + "\"status\": 0\n" + + "}"; + + List result = read(json, "$.datas.selling['3','206'].*"); + + assertThat(result).containsExactly(26452067,31625950,32381852,32489262); + } + @Test public void full_ones_can_be_filtered() { String json = "[\n" + @@ -447,7 +513,7 @@ public class IssuesTest extends BaseTest { " ]\n" + "}\n"; - List result = JsonPath.read(json, "$.a.*.b.*.c"); + List result = read(json, "$.a.*.b.*.c"); assertThat(result).containsExactly("foo"); @@ -503,7 +569,7 @@ public class IssuesTest extends BaseTest { " ]\n" + "}]"; - List problems = JsonPath.read(json, "$..narratives[?(@.lastRule==true)].message"); + List problems = read(json, "$..narratives[?(@.lastRule==true)].message"); assertThat(problems).containsExactly("Chain does not have a discovery event. Possible it was cut by the date that was picked", "No start transcoding events found"); } @@ -563,7 +629,7 @@ public class IssuesTest extends BaseTest { + " ]\n" + "}"; - List result = JsonPath.read(json, "$.logs[?(@.message == 'it\\'s here')].message"); + List result = read(json, "$.logs[?(@.message == 'it\\'s here')].message"); assertThat(result).containsExactly("it's here"); } @@ -596,7 +662,7 @@ public class IssuesTest extends BaseTest { " }\n" + "}"; - List res = JsonPath.read(json, "$.c.*.url[2]"); + List res = read(json, "$.c.*.url[2]"); assertThat(res).containsExactly("url5"); } @@ -775,7 +841,7 @@ public class IssuesTest extends BaseTest { " }\n" + "]"; - List> result = JsonPath.read(json, "$[?(@.foo)]"); + List> result = read(json, "$[?(@.foo)]"); assertThat(result).extracting("foo").containsExactly("1", null); } @@ -796,12 +862,12 @@ public class IssuesTest extends BaseTest { " }\n" + "]"; - List result = JsonPath.read(json, "$[?(@.foo != null)].foo.bar"); + List result = read(json, "$[?(@.foo != null)].foo.bar"); assertThat(result).containsExactly("0"); - result = JsonPath.read(json, "$[?(@.foo.bar)].foo.bar"); + result = read(json, "$[?(@.foo.bar)].foo.bar"); assertThat(result).containsExactly("0"); } @@ -821,7 +887,7 @@ public class IssuesTest extends BaseTest { " }\n" + "]"; - List result = JsonPath.read(json, "$[2]['d'][?(@.random)]['date']"); + List result = read(json, "$[2]['d'][?(@.random)]['date']"); assertThat(result).containsExactly(1234); } @@ -833,7 +899,7 @@ public class IssuesTest extends BaseTest { String json = "{ \"valid key[@num = 2]\" : \"value\" }"; - String result = JsonPath.read(json, "$['valid key[@num = 2]']"); + String result = read(json, "$['valid key[@num = 2]']"); Assertions.assertThat(result).isEqualTo("value"); } @@ -864,7 +930,7 @@ public class IssuesTest extends BaseTest { " \"expensive\": 10\n" + "}"; - List numbers = JsonPath.read(json, "$.store.book[?(@.price <= 90)].price"); + List numbers = read(json, "$.store.book[?(@.price <= 90)].price"); assertThat(numbers).containsExactly(8.95D, 12.99D, 8.99D, 22.99D); }