Browse Source

Refactored split path.

pull/3/head
kalle 13 years ago
parent
commit
a5e0d27304
  1. 23
      json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java
  2. 6
      json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java
  3. 6
      json-path/pom.xml
  4. 173
      json-path/src/main/java/com/jayway/jsonpath/PathUtil.java
  5. 3
      json-path/src/main/java/com/jayway/jsonpath/filter/ListEvalFilter.java
  6. 1
      json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java
  7. 47
      json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java
  8. 5
      json-path/src/test/java/com/jayway/jsonpath/PathUtilTest.java
  9. 107
      json-path/src/test/java/com/jayway/jsonpath/SplitPathFragmentsTest.java

23
json-path-assert/src/main/java/com/jayway/jsonassert/impl/JsonAsserterImpl.java

@ -34,28 +34,11 @@ public class JsonAsserterImpl implements JsonAsserter {
*/
@SuppressWarnings("unchecked")
public <T> JsonAsserter assertThat(String path, Matcher<T> matcher) {
T obj = JsonPath.<T>read(jsonObject, path);
if (!matcher.matches(obj)) {
String reason = "When processing json path: " + path;
if (!matcher.matches(JsonPath.<T>read(jsonObject, path))) {
System.out.println(JsonPath.read(jsonObject, path).toString());
throw new AssertionError(reason + matcher.toString());
throw new AssertionError(String.format("JSON doesn't match.\nExpected:\n%s\nActual:\n%s", matcher.toString(), obj));
}
/*
if (PathUtil.isPathDefinite(path)) {
if (!matcher.matches(JsonPath.<T>readOne(jsonObject, path))) {
throw new AssertionError(reason + matcher.toString());
}
//MatcherAssert.assertThat(reason, JsonPath.<T>readOne(jsonObject, path), matcher);
} else {
if (!matcher.matches(JsonPath.<T>read(jsonObject, path))) {
throw new AssertionError(reason + matcher.toString());
}
//MatcherAssert.assertThat(reason, (T) JsonPath.<T>read(jsonObject, path), matcher);
} */
return this;
}

6
json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java

@ -50,6 +50,12 @@ public class JsonAssertTest {
"}";
@Test(expected = AssertionError.class)
public void failed_error_message() throws Exception {
with(JSON).assertThat("$.store.book[0].category", endsWith("foobar"));
}
@Test
public void links_document() throws Exception {

6
json-path/pom.xml

@ -44,12 +44,6 @@
<artifactId>commons-lang</artifactId>
</dependency>
<dependency>
<groupId>net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>1.0.6.3</version>
</dependency>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -->
<!-- test dependencies -->

173
json-path/src/main/java/com/jayway/jsonpath/PathUtil.java

@ -2,7 +2,7 @@ package com.jayway.jsonpath;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Queue;
/**
* User: kalle stenflo
@ -33,7 +33,6 @@ public class PathUtil {
* @return true if path is definite (points to single item)
*/
public static boolean isPathDefinite(String jsonPath) {
//return !jsonPath.replaceAll("\"[^\"\\\\\\n\r]*\"", "").matches(".*(\\.\\.|\\*|\\[[\\\\/]|\\?|,|:|>|\\(|<|=|\\+).*");
return !jsonPath.replaceAll("\"[^\"\\\\\\n\r]*\"", "").matches(".*(\\.\\.|\\*|\\[[\\\\/]|\\?|,|:\\s?\\]|\\[\\s?:|>|\\(|<|=|\\+).*");
}
@ -47,34 +46,166 @@ public class PathUtil {
*/
public static List<String> splitPath(String jsonPath) {
if (!jsonPath.startsWith("$") && !jsonPath.startsWith("$[")) {
jsonPath = "$." + jsonPath;
}
LinkedList<String> fragments = new LinkedList<String>();
if (!jsonPath.startsWith("$.")) {
jsonPath = "$." + jsonPath;
Queue<Character> pathQueue = new LinkedList<Character>();
for (char b : jsonPath.toCharArray()) {
pathQueue.add(b);
}
jsonPath = jsonPath.replace("$['","$.['")
.replaceAll("\\['(\\w+)\\.(\\w+)']", "['$1~$2']")
.replace("']['","'].['" )
.replace("..", ".~~.")
.replace("[", ".[")
.replace("@.", "@")
.replace("['", "")
.replace("']", "");
while (!pathQueue.isEmpty()) {
skip(pathQueue, ' ');
char current = pathQueue.peek();
switch (current) {
case '$':
fragments.add(Character.toString(current));
pathQueue.poll();
break;
case '.':
pathQueue.poll();
if (pathQueue.peek().equals('.')) {
pathQueue.poll();
fragments.add("..");
assertNotInvalidPeek(pathQueue, '.');
}
break;
String[] split = jsonPath.split("\\.");
case '[':
fragments.add(extract(pathQueue, true, ']'));
break;
default:
fragments.add(extract(pathQueue, false, '[', '.'));
for (int i = 0; i < split.length; i++) {
if (split[i].trim().isEmpty()) {
continue;
}
fragments.add(split[i].replace("@", "@.").replace("~", "."));
}
return fragments;
}
//for (String fragment : fragments) {
// System.out.println(fragment);
//}
return fragments;
private static String extract(Queue<Character> pathQueue, boolean includeSopChar, char... stopChars) {
StringBuilder sb = new StringBuilder();
while (!pathQueue.isEmpty() && (!isStopChar(pathQueue.peek().charValue(), stopChars))) {
char c = pathQueue.poll();
if (isStopChar(c, stopChars)) {
if (includeSopChar) {
sb.append(c);
}
} else {
sb.append(c);
}
}
if (includeSopChar) {
assertValidPeek(pathQueue, false, stopChars);
sb.append(pathQueue.poll());
} else {
assertValidPeek(pathQueue, true, stopChars);
}
return unWrapProperty(sb);
}
private static String unWrapProperty(StringBuilder sb) {
String src = sb.toString();
src = trim(src, "'");
src = trim(src, ")");
src = trim(src, "(");
src = trimLeft(src, "?");
src = trimLeft(src, "@");
if (src.length() > 5 && src.subSequence(0, 2).equals("['")) {
src = src.substring(2);
src = src.substring(0, src.length() - 2);
}
return src.trim();
}
private static String trim(String src, String trim) {
return trimLeft(trimRight(src, trim), trim);
}
private static String trimRight(String src, String trim) {
String scanFor = trim + " ";
if (src.contains(scanFor)) {
while (src.contains(scanFor)) {
src = src.replace(scanFor, trim);
}
}
return src;
}
private static String trimLeft(String src, String trim) {
String scanFor = " " + trim;
if (src.contains(scanFor)) {
while (src.contains(scanFor)) {
src = src.replace(scanFor, trim);
}
}
return src;
}
private static boolean isStopChar(char c, char... scanFor) {
boolean found = false;
for (char check : scanFor) {
if (check == c) {
found = true;
break;
}
}
return found;
}
private static void skip(Queue<Character> pathQueue, char target) {
if (pathQueue.isEmpty()) {
return;
}
while (pathQueue.peek().charValue() == target) {
pathQueue.poll();
}
}
private static void assertNotInvalidPeek(Queue<Character> pathQueue, char... invalidChars) {
if (pathQueue.isEmpty()) {
return;
}
char peek = pathQueue.peek();
for (char check : invalidChars) {
if (check == peek) {
throw new InvalidPathException("Char: " + peek + " at current position is not valid!");
}
}
}
private static void assertValidPeek(Queue<Character> pathQueue, boolean acceptEmpty, char... validChars) {
if (pathQueue.isEmpty() && acceptEmpty) {
return;
}
if (pathQueue.isEmpty()) {
throw new InvalidPathException("Path is incomplete");
}
boolean found = false;
char peek = pathQueue.peek();
for (char check : validChars) {
if (check == peek) {
found = true;
break;
}
}
if (!found) {
throw new InvalidPathException("Path is invalid");
}
}
}

3
json-path/src/main/java/com/jayway/jsonpath/filter/ListEvalFilter.java

@ -17,8 +17,7 @@ import java.util.regex.Pattern;
*/
public class ListEvalFilter extends JsonPathFilterBase {
public static final Pattern PATTERN = Pattern.compile("\\[\\s?\\?\\s?\\(\\s?@.(\\w+)\\s?([=<>]+)\\s?(.*)\\s?\\)\\s?\\]"); //[?( @.title< 'ko')]
public static final Pattern PATTERN = Pattern.compile("\\[\\s?\\?\\s?\\(\\s?@.(.*?)\\s?([=<>]+)\\s?(.*)\\s?\\)\\s?\\]"); //[?( @.title< 'ko')]
private final String pathFragment;

1
json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java

@ -15,6 +15,7 @@ import static org.junit.Assert.assertTrue;
public class ExpressionEvalTest {
@Test
public void long_eval() throws Exception {

47
json-path/src/test/java/com/jayway/jsonpath/JsonPathTest.java

@ -4,7 +4,6 @@ import org.junit.Test;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasItems;
@ -55,6 +54,27 @@ public class JsonPathTest {
" }\n" +
"}";
private final static String PRODUCT_JSON = "{\n" +
"\t\"product\": [ {\n" +
"\t \"version\": \"A\", \n" +
"\t \"codename\": \"Seattle\", \n" +
"\t \"attr.with.dot\": \"A\"\n" +
"\t},\n" +
"\t{\n" +
"\t \"version\": \"4.0\", \n" +
"\t \"codename\": \"Montreal\", \n" +
"\t \"attr.with.dot\": \"B\"\n" +
"\t}]\n" +
"}";
private final static String ARRAY_EXPAND = "[{\"parent\": \"ONE\", \"child\": {\"name\": \"NAME_ONE\"}}, [{\"parent\": \"TWO\", \"child\": {\"name\": \"NAME_TWO\"}}]]";
@Test
public void array_start_expands() throws Exception {
assertThat(JsonPath.<List<String>>read(ARRAY_EXPAND, "$[?(@.parent = 'ONE')].child.name"), hasItems("NAME_ONE"));
}
@Test
public void bracket_notation_can_be_used_in_path() throws Exception {
@ -72,6 +92,14 @@ public class JsonPathTest {
System.out.println(matches);
}
@Test
public void filter_an_array_on_index() throws Exception {
Integer matches = JsonPath.read(ARRAY, "$.[1].value");
assertEquals(new Integer(2), matches);
System.out.println(matches);
}
@Test
public void read_path_with_colon() throws Exception {
@ -85,11 +113,8 @@ public class JsonPathTest {
Map result = JsonPath.read(DOCUMENT, "$.store");
assertEquals(2, result.values().size());
}
@Test
public void read_store_book_1() throws Exception {
@ -175,6 +200,20 @@ public class JsonPathTest {
}
@Test
public void dot_in_predicate_works() throws Exception {
assertThat(JsonPath.<List<String>>read(PRODUCT_JSON, "$.product[?(@.version='4.0')].codename"), hasItems("Montreal"));
}
@Test
public void dots_in_predicate_works() throws Exception {
assertThat(JsonPath.<List<String>>read(PRODUCT_JSON, "$.product[?(@.attr.with.dot='A')].codename"), hasItems("Seattle"));
}
@Test
public void all_books_with_category_reference() throws Exception {

5
json-path/src/test/java/com/jayway/jsonpath/PathUtilTest.java

@ -15,12 +15,13 @@ public class PathUtilTest {
@Test
public void wildcard_is_not_definite() throws Exception {
public void path_is_not_definite() throws Exception {
assertFalse(PathUtil.isPathDefinite("$..book[0]"));
assertFalse(PathUtil.isPathDefinite("$.books[*]"));
}
@Test
public void is_definite() throws Exception {
public void path_is_definite() throws Exception {
assertTrue(PathUtil.isPathDefinite("$.definite.this.is"));
assertTrue(PathUtil.isPathDefinite("$.definite:this.is"));
assertTrue(PathUtil.isPathDefinite("rows[0].id"));

107
json-path/src/test/java/com/jayway/jsonpath/SplitPathFragmentsTest.java

@ -1,10 +1,13 @@
package com.jayway.jsonpath;
import org.hamcrest.Matcher;
import org.junit.Test;
import static org.hamcrest.Matchers.hasItemInArray;
import java.util.List;
import static org.hamcrest.Matchers.hasItems;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* Created by IntelliJ IDEA.
@ -14,69 +17,93 @@ import static org.junit.Assert.assertThat;
*/
public class SplitPathFragmentsTest {
/*
1. "$..book[-1:].foo.bar"
2. "$.store.book[*].author"
3. "$..author"
4. "$.store.*"
5. "$.store..price"
6. "$..book[(@.length-1)]"
7. "$..book[-1:]
8. "$..book[0,1]"
9. "$..book[:2]"
10. "$..book[?(@.isbn)]"
11. "$..book[?(@.price<10)]"
12. "$..*"
*/
@Test
public void bracket_notation_can_be_split() throws Exception {
assertThat(PathUtil.splitPath("$.['store'].['price']"), hasItems("$", "store", "price"));
assertThat(PathUtil.splitPath("$['store']['price']"), hasItems("$", "store", "price"));
assertThat(PathUtil.splitPath("['store']['price']"), hasItems("$", "store", "price"));
assertThat(PathUtil.splitPath("['store'].price"), hasItems("$", "store", "price"));
public void valid_path_is_split_correctly() throws Exception {
assertThat(PathUtil.splitPath("$.['store book'].['price list']"), hasItems("$", "store book", "price list"));
assertPath("$.store[*]", hasItems("$", "store", "[*]"));
assertThat(PathUtil.splitPath("$.['store.book'].['price.list']"), hasItems("$", "store.book", "price.list"));
}
assertPath("$", hasItems("$"));
@Test
public void fragments_are_split_correctly() throws Exception {
assertPath("$..*", hasItems("$", "..", "*"));
assertPath("$.store", hasItems("$", "store"));
assertPath("$.store.*", hasItems("$", "store", "*"));
assertPath("$.store[*].name", hasItems("$", "store", "[*]", "name"));
assertPath("$..book[-1:].foo.bar", hasItems("$", "..", "book", "[-1:]", "foo", "bar"));
assertPath("$..book[?(@.isbn)]", hasItems("$", "..", "book", "[?(@.isbn)]"));
assertPath("['store'].['price']", hasItems("$", "store", "price"));
assertPath("$.['store'].['price']", hasItems("$", "store", "price"));
assertThat(PathUtil.splitPath("$..book[-1:].foo.bar"), hasItems("$", "..", "[-1:]", "foo", "bar"));
assertPath("$.['store']['price']", hasItems("$", "store", "price"));
assertThat(PathUtil.splitPath("$.store.book[*].author"), hasItems("$", "store", "book", "[*]", "author"));
assertPath("$.['store'].price", hasItems("$", "store", "price"));
assertThat(PathUtil.splitPath("$..author"), hasItems("$", "..", "author"));
assertPath("$.['store space']['price space']", hasItems("$", "store space", "price space"));
assertThat(PathUtil.splitPath("$.store.*"), hasItems("$", "store", "*"));
assertPath("$.['store']['nice.price']", hasItems("$", "store", "nice.price"));
assertThat(PathUtil.splitPath("$.store..price"), hasItems("$", "store", "..", "price"));
assertPath("$..book[?(@.price<10)]", hasItems("$", "..", "book", "[?(@.price<10)]"));
assertThat(PathUtil.splitPath("$..book[(@.length-1)]"), hasItems("$", "..", "book", "[(@.length-1)]"));
assertPath("$..book[?(@.price<10)]", hasItems("$", "..", "book", "[?(@.price<10)]"));
assertThat(PathUtil.splitPath("$..book[-1:]"), hasItems("$", "..", "book", "[-1:]"));
assertPath("$.store.book[*].author", hasItems("$", "store", "book", "[*]", "author"));
assertThat(PathUtil.splitPath("$..book[0,1]"), hasItems("$", "..", "book", "[0,1]"));
assertPath("$.store..price", hasItems("$", "store", "..", "price"));
assertThat(PathUtil.splitPath("$..book[:2]"), hasItems("$", "..", "book", "[:2]"));
}
@Test
public void white_space_are_removed() throws Exception {
assertPath("$.[ 'store' ]", hasItems("$", "store"));
assertPath("$.[ 'store' ]", hasItems("$", "store"));
assertThat(PathUtil.splitPath("$..book[?(@.isbn)]"), hasItems("$", "..", "book", "[?(@.isbn)]"));
assertPath("$..book[ ?(@.price<10) ]", hasItems("$", "..", "book", "[?(@.price<10)]"));
assertThat(PathUtil.splitPath("$..book[?(@.price<10)]"), hasItems("$", "..", "book", "[?(@.price<10)]"));
assertPath("$..book[?(@.price<10 )]", hasItems("$", "..", "book", "[?(@.price<10)]"));
assertThat(PathUtil.splitPath("$..*"), hasItems("$", "..", "*"));
assertPath("$..book[?( @.price<10)]", hasItems("$", "..", "book", "[?(@.price<10)]"));
assertThat(PathUtil.splitPath("$.[0][1].author"), hasItems("$", "[0]", "[1]", "author"));
assertPath("$..book[ ?(@.price<10)]", hasItems("$", "..", "book", "[?(@.price<10)]"));
}
assertThat(PathUtil.splitPath("$.[0].[1].author"), hasItems("$", "[0]", "[1]", "author"));
@Test
public void invalid_path_throws_exception() throws Exception {
assertPathInvalid("$...*");
}
assertThat(PathUtil.splitPath("$.foo:bar.author"), hasItems("$", "foo:bar", "author"));
//----------------------------------------------------------------
//
// Helpers
//
//----------------------------------------------------------------
private void assertPathInvalid(String path) {
try {
PathUtil.splitPath(path);
assertTrue("Expected exception!", false);
} catch (InvalidPathException expected) {}
}
private void assertPath(String path, Matcher<Iterable<String>> matcher) {
System.out.println("PATH: " + path);
List<String> fragments = PathUtil.splitPath(path);
for (String fragment : fragments) {
System.out.println(fragment);
}
assertThat(fragments, matcher);
System.out.println("----------------------------------");
}
}

Loading…
Cancel
Save