Browse Source

started a simplistic JSONPath implementation

pull/1/merge
kalle 14 years ago
parent
commit
50da66a744
  1. 4
      json-assert/pom.xml
  2. 26
      json-assert/src/main/java/com/jayway/jsonassert/JSONAssert.java
  3. 17
      json-assert/src/main/java/com/jayway/jsonassert/JSONAsserter.java
  4. 17
      json-assert/src/main/java/com/jayway/jsonassert/JsonPath.java
  5. 23
      json-assert/src/main/java/com/jayway/jsonassert/impl/JSONAsserterImpl.java
  6. 40
      json-assert/src/main/java/com/jayway/jsonassert/impl/JSONPath.java
  7. 69
      json-assert/src/main/java/com/jayway/jsonassert/impl/JSONPathFragment.java
  8. 113
      json-assert/src/main/java/com/jayway/jsonassert/impl/JSONReaderImpl.java
  9. 185
      json-assert/src/main/java/com/jayway/jsonassert/impl/JsonPathImpl.java
  10. 72
      json-assert/src/main/java/com/jayway/jsonassert/impl/Path.java
  11. 122
      json-assert/src/main/java/com/jayway/jsonassert/impl/PathFragment.java
  12. 18
      json-assert/src/test/java/com/jayway/jsonassert/JSONAssertTest.java
  13. 157
      json-assert/src/test/java/com/jayway/jsonassert/JSONReaderTest.java
  14. 278
      json-assert/src/test/java/com/jayway/jsonassert/JsonPathTest.java
  15. 27
      json-assert/src/test/resources/json_array.json
  16. 6
      pom.xml

4
json-assert/pom.xml

@ -30,6 +30,10 @@
<url>http://maven.apache.org</url> <url>http://maven.apache.org</url>
<dependencies> <dependencies>
<dependency>
<groupId>commons-jxpath</groupId>
<artifactId>commons-jxpath</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.googlecode.json-simple</groupId> <groupId>com.googlecode.json-simple</groupId>

26
json-assert/src/main/java/com/jayway/jsonassert/JSONAssert.java

@ -1,7 +1,7 @@
package com.jayway.jsonassert; package com.jayway.jsonassert;
import com.jayway.jsonassert.impl.JSONAsserterImpl; import com.jayway.jsonassert.impl.JsonAsserterImpl;
import com.jayway.jsonassert.impl.JSONReaderImpl; import com.jayway.jsonassert.impl.JsonReaderImpl;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
@ -12,7 +12,7 @@ import java.text.ParseException;
* Date: 1/24/11 * Date: 1/24/11
* Time: 9:31 PM * Time: 9:31 PM
*/ */
public class JSONAssert { public class JsonAssert {
/** /**
* Creates a JSONReader * Creates a JSONReader
@ -21,8 +21,8 @@ public class JSONAssert {
* @return a new reader * @return a new reader
* @throws ParseException * @throws ParseException
*/ */
public static JSONReader parse(String jsonDoc) throws ParseException { public static JsonPath parse(String jsonDoc) throws ParseException {
return JSONReaderImpl.parse(jsonDoc); return JsonReaderImpl.parse(jsonDoc);
} }
/** /**
@ -33,7 +33,7 @@ public class JSONAssert {
* @throws ParseException document could not pe parsed * @throws ParseException document could not pe parsed
* @throws IOException * @throws IOException
*/ */
public static JSONReader parse(Reader reader) throws ParseException, IOException { public static JsonPath parse(Reader reader) throws ParseException, IOException {
return parse(reader, false); return parse(reader, false);
} }
@ -45,10 +45,10 @@ public class JSONAssert {
* @throws ParseException document could not pe parsed * @throws ParseException document could not pe parsed
* @throws IOException * @throws IOException
*/ */
public static JSONReader parse(Reader reader, boolean closeReader) throws ParseException, IOException { public static JsonPath parse(Reader reader, boolean closeReader) throws ParseException, IOException {
JSONReader jsonReader = null; JsonPath jsonReader = null;
try { try {
jsonReader = JSONReaderImpl.parse(reader); jsonReader = JsonReaderImpl.parse(reader);
} finally { } finally {
if(closeReader){ if(closeReader){
try { try {
@ -66,8 +66,8 @@ public class JSONAssert {
* @return a JSON asserter initialized with the provided document * @return a JSON asserter initialized with the provided document
* @throws ParseException when the given JSON could not be parsed * @throws ParseException when the given JSON could not be parsed
*/ */
public static JSONAsserter with(String json) throws ParseException { public static JsonAsserter with(String json) throws ParseException {
return new JSONAsserterImpl(JSONReaderImpl.parse(json)); return new JsonAsserterImpl(JsonReaderImpl.parse(json));
} }
/** /**
@ -77,8 +77,8 @@ public class JSONAssert {
* @return a JSON asserter initialized with the provided document * @return a JSON asserter initialized with the provided document
* @throws ParseException when the given JSON could not be parsed * @throws ParseException when the given JSON could not be parsed
*/ */
public static JSONAsserter with(Reader reader) throws ParseException, IOException { public static JsonAsserter with(Reader reader) throws ParseException, IOException {
return new JSONAsserterImpl(JSONReaderImpl.parse(reader)); return new JsonAsserterImpl(JsonReaderImpl.parse(reader));
} }
} }

17
json-assert/src/main/java/com/jayway/jsonassert/JSONAsserter.java

@ -3,19 +3,18 @@ package com.jayway.jsonassert;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
/** /**
* Created by IntelliJ IDEA.
* User: kallestenflo * User: kallestenflo
* Date: 1/24/11 * Date: 1/24/11
* Time: 9:22 PM * Time: 9:22 PM
*/ */
public interface JSONAsserter { public interface JsonAsserter {
/** /**
* Gives access to the {@link JSONReader} used to base the assertions on * Gives access to the {@link JsonPath} used to base the assertions on
* *
* @return the underlying reader * @return the underlying reader
*/ */
JSONReader reader(); JsonPath reader();
/** /**
* Asserts that object specified by path satisfies the condition specified by matcher. * Asserts that object specified by path satisfies the condition specified by matcher.
@ -32,7 +31,7 @@ public interface JSONAsserter {
* @param <T> the static type accepted by the matcher * @param <T> the static type accepted by the matcher
* @return this to allow fluent assertion chains * @return this to allow fluent assertion chains
*/ */
<T> JSONAsserter assertThat(String path, Matcher<T> matcher); <T> JsonAsserter assertThat(String path, Matcher<T> matcher);
/** /**
* Asserts that object specified by path is equal to the expected value. * Asserts that object specified by path is equal to the expected value.
@ -43,7 +42,7 @@ public interface JSONAsserter {
* @param <T> the static type that should be returned by the path * @param <T> the static type that should be returned by the path
* @return this to allow fluent assertion chains * @return this to allow fluent assertion chains
*/ */
<T> JSONAsserter assertEquals(String path, T expected); <T> JsonAsserter assertEquals(String path, T expected);
/** /**
* Asserts that object specified by path is null. If it is not, an AssertionError * Asserts that object specified by path is null. If it is not, an AssertionError
@ -52,7 +51,7 @@ public interface JSONAsserter {
* @param path the json path specifying the value that should be null * @param path the json path specifying the value that should be null
* @return this to allow fluent assertion chains * @return this to allow fluent assertion chains
*/ */
JSONAsserter assertNull(String path); JsonAsserter assertNull(String path);
/** /**
* Asserts that object specified by path is NOT null. If it is, an AssertionError * Asserts that object specified by path is NOT null. If it is, an AssertionError
@ -61,7 +60,7 @@ public interface JSONAsserter {
* @param path the json path specifying the value that should be NOT null * @param path the json path specifying the value that should be NOT null
* @return this to allow fluent assertion chains * @return this to allow fluent assertion chains
*/ */
<T> JSONAsserter assertNotNull(String path); <T> JsonAsserter assertNotNull(String path);
/** /**
* Syntactic sugar to allow chaining assertions with a separating and() statement * Syntactic sugar to allow chaining assertions with a separating and() statement
@ -73,5 +72,5 @@ public interface JSONAsserter {
* *
* @return this to allow fluent assertion chains * @return this to allow fluent assertion chains
*/ */
JSONAsserter and(); JsonAsserter and();
} }

17
json-assert/src/main/java/com/jayway/jsonassert/JSONReader.java → json-assert/src/main/java/com/jayway/jsonassert/JsonPath.java

@ -4,12 +4,19 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* Created by IntelliJ IDEA.
* User: kallestenflo * User: kallestenflo
* Date: 1/24/11 * Date: 1/24/11
* Time: 9:29 PM * Time: 9:29 PM
*/ */
public interface JSONReader { public interface JsonPath {
/**
* Get a new reader with the given path as root
*
* @param path to extract a reader for
* @return new reader
*/
JsonPath getReader(String path);
/** /**
* @param path * @param path
@ -25,9 +32,9 @@ public interface JSONReader {
/** /**
* @param path * @param path
* @return * @returnÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ
*/ */
Object get(String path); <T> T get(String path);
/** /**
* @param path * @param path
@ -64,5 +71,5 @@ public interface JSONReader {
* @param path * @param path
* @return * @return
*/ */
Map getMap(String path); Map<String, Object> getMap(String path);
} }

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

@ -1,8 +1,8 @@
package com.jayway.jsonassert.impl; package com.jayway.jsonassert.impl;
import com.jayway.jsonassert.JSONAsserter; import com.jayway.jsonassert.JsonAsserter;
import com.jayway.jsonassert.JSONReader; import com.jayway.jsonassert.JsonPath;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert; import org.hamcrest.MatcherAssert;
@ -13,9 +13,9 @@ import static org.hamcrest.Matchers.*;
* Date: 1/21/11 * Date: 1/21/11
* Time: 3:43 PM * Time: 3:43 PM
*/ */
public class JSONAsserterImpl implements JSONAsserter { public class JsonAsserterImpl implements JsonAsserter {
private final JSONReader reader; private final JsonPath reader;
/** /**
@ -23,21 +23,22 @@ public class JSONAsserterImpl implements JSONAsserter {
* *
* @param reader initialized with the JSON document to be asserted upon * @param reader initialized with the JSON document to be asserted upon
*/ */
public JSONAsserterImpl(JSONReader reader) { public JsonAsserterImpl(JsonPath reader) {
this.reader = reader; this.reader = reader;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public JSONReader reader() { public JsonPath reader() {
return reader; return reader;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public <T> JSONAsserter assertThat(String path, Matcher<T> matcher) { @SuppressWarnings("unchecked")
public <T> JsonAsserter assertThat(String path, Matcher<T> matcher) {
MatcherAssert.assertThat((T) reader.get(path), matcher); MatcherAssert.assertThat((T) reader.get(path), matcher);
return this; return this;
} }
@ -45,28 +46,28 @@ public class JSONAsserterImpl implements JSONAsserter {
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public <T> JSONAsserter assertEquals(String path, T expected) { public <T> JsonAsserter assertEquals(String path, T expected) {
return assertThat(path, equalTo(expected)); return assertThat(path, equalTo(expected));
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public JSONAsserter assertNull(String path) { public JsonAsserter assertNull(String path) {
return assertThat(path, nullValue()); return assertThat(path, nullValue());
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public <T> JSONAsserter assertNotNull(String path) { public <T> JsonAsserter assertNotNull(String path) {
return assertThat(path, notNullValue()); return assertThat(path, notNullValue());
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public JSONAsserter and() { public JsonAsserter and() {
return this; return this;
} }

40
json-assert/src/main/java/com/jayway/jsonassert/impl/JSONPath.java

@ -1,40 +0,0 @@
package com.jayway.jsonassert.impl;
import java.util.LinkedList;
import java.util.Queue;
/**
* User: kalle stenflo
* Date: 1/23/11
* Time: 1:52 PM
*/
class JSONPath {
private final Queue<JSONPathFragment> path;
JSONPath(String path) {
this.path = compilePathFragments(path);
}
boolean hasMoreFragments(){
return !path.isEmpty();
}
JSONPathFragment nextFragment(){
return path.poll();
}
private Queue<JSONPathFragment> compilePathFragments(String path) {
//TODO: this needs some attention but will work for now
Queue<JSONPathFragment> processed = new LinkedList<JSONPathFragment>();
for (String fragment : path.split("[\\.|\\[]")) {
if (fragment.trim().length() > 0) {
String compiledFragment = fragment.endsWith("]") ? "[" + fragment : fragment;
processed.add(new JSONPathFragment(compiledFragment));
}
}
return processed;
}
}

69
json-assert/src/main/java/com/jayway/jsonassert/impl/JSONPathFragment.java

@ -1,69 +0,0 @@
package com.jayway.jsonassert.impl;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* User: kalle stenflo
* Date: 1/23/11
* Time: 1:55 PM
*/
class JSONPathFragment {
private static final Pattern ARRAY_POSITION_PATTER = Pattern.compile("\\[(\\d*)\\]");
private static final Pattern GROOVY_POSITION_PATTER = Pattern.compile("get\\((\\d*)\\)");
private static final Pattern ARRAY_WILDCARD_PATTER = Pattern.compile("\\[\\*\\]");
private static final Pattern GROOVY_WILDCARD_PATTER = Pattern.compile("get\\(\\*\\)");
private final String fragment;
JSONPathFragment(String fragment) {
this.fragment = fragment;
}
String value() {
return fragment;
}
String appendToPath(String path){
StringBuilder builder = new StringBuilder(path);
if(ARRAY_POSITION_PATTER.matcher(fragment).matches()){
builder.append("[").append(getArrayIndex()).append("]");
}
else if(GROOVY_POSITION_PATTER.matcher(fragment).matches()){
builder.append(path.isEmpty()?"":".").append("get(").append(getArrayIndex()).append(")");
}
else if(ARRAY_WILDCARD_PATTER.matcher(fragment).matches()){
builder.append("[*]");
}
else if(GROOVY_WILDCARD_PATTER.matcher(fragment).matches()){
builder.append(path.isEmpty()?"":".").append("get(*)");
}
else {
builder.append(path.isEmpty()?"":".").append(fragment);
}
return builder.toString();
}
boolean isArrayIndex() {
return ARRAY_POSITION_PATTER.matcher(fragment).matches() || GROOVY_POSITION_PATTER.matcher(fragment).matches();
}
boolean isArrayWildcard() {
return ARRAY_WILDCARD_PATTER.matcher(fragment).matches() || GROOVY_WILDCARD_PATTER.matcher(fragment).matches();
}
int getArrayIndex() {
Matcher matcher = ARRAY_POSITION_PATTER.matcher(fragment);
if (matcher.matches()) {
return Integer.parseInt(matcher.group(1));
}
matcher = GROOVY_POSITION_PATTER.matcher(fragment);
if (matcher.matches()) {
return Integer.parseInt(matcher.group(1));
}
throw new IllegalArgumentException("not an array index fragment");
}
}

113
json-assert/src/main/java/com/jayway/jsonassert/impl/JSONReaderImpl.java

@ -1,7 +1,7 @@
package com.jayway.jsonassert.impl; package com.jayway.jsonassert.impl;
import com.jayway.jsonassert.InvalidPathException; import com.jayway.jsonassert.InvalidPathException;
import com.jayway.jsonassert.JSONReader; import com.jayway.jsonassert.JsonPath;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser; import org.json.simple.parser.JSONParser;
@ -20,7 +20,7 @@ import static org.apache.commons.lang.Validate.notNull;
* Date: 1/20/11 * Date: 1/20/11
* Time: 4:27 PM * Time: 4:27 PM
*/ */
public class JSONReaderImpl implements JSONReader { public class JsonReaderImpl implements JsonPath {
private static final JSONParser JSON_PARSER = new JSONParser(); private static final JSONParser JSON_PARSER = new JSONParser();
@ -29,9 +29,9 @@ public class JSONReaderImpl implements JSONReader {
private String currentPath; private String currentPath;
public static synchronized JSONReader parse(Reader reader) throws java.text.ParseException, IOException { public static synchronized JsonPath parse(Reader reader) throws java.text.ParseException, IOException {
try { try {
return new JSONReaderImpl(JSON_PARSER.parse(reader)); return new JsonReaderImpl(JSON_PARSER.parse(reader));
} catch (IOException e) { } catch (IOException e) {
throw e; throw e;
} catch (ParseException e) { } catch (ParseException e) {
@ -39,19 +39,32 @@ public class JSONReaderImpl implements JSONReader {
} }
} }
public static synchronized JSONReader parse(String jsonDoc) throws java.text.ParseException { public static synchronized JsonPath parse(String jsonDoc) throws java.text.ParseException {
try { try {
return new JSONReaderImpl(JSON_PARSER.parse(jsonDoc)); return new JsonReaderImpl(JSON_PARSER.parse(jsonDoc));
} catch (ParseException e) { } catch (ParseException e) {
throw new java.text.ParseException(e.getMessage(), e.getPosition()); throw new java.text.ParseException(e.getMessage(), e.getPosition());
} }
} }
private JSONReaderImpl(Object root) { private JsonReaderImpl(Object root) {
notNull(root, "root object can not be null"); notNull(root, "root object can not be null");
this.root = root; this.root = root;
} }
/**
* {@inheritDoc}
*/
public JsonPath getReader(String path) {
Object jsonObject = get(path);
if (!isArray(jsonObject) && !isDocument(jsonObject)) {
throw new InvalidPathException("path points to a leaf that is not a JSON document or Array");
}
return new JsonReaderImpl(jsonObject);
}
/** /**
* {@inheritDoc} * {@inheritDoc}
@ -76,8 +89,9 @@ public class JSONReaderImpl implements JSONReader {
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public Object get(String path) { @SuppressWarnings("unchecked")
return getByPath(Object.class, path); public <T> T get(String path) {
return (T) getByPath(Object.class, path);
} }
/** /**
@ -118,7 +132,7 @@ public class JSONReaderImpl implements JSONReader {
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public Map getMap(String path) { public Map<String, Object> getMap(String path) {
return getByPath(Map.class, path); return getByPath(Map.class, path);
} }
@ -129,7 +143,7 @@ public class JSONReaderImpl implements JSONReader {
// //
//------------------------------------------------------------ //------------------------------------------------------------
/*
private <T> T getByPath(Class<T> clazz, String stringPath) { private <T> T getByPath(Class<T> clazz, String stringPath) {
currentPath = ""; currentPath = "";
Object current = this.root; Object current = this.root;
@ -137,20 +151,87 @@ public class JSONReaderImpl implements JSONReader {
while (path.hasMoreFragments()) { while (path.hasMoreFragments()) {
JSONPathFragment fragment = path.nextFragment(); JSONPathFragment fragment = path.poll();
currentPath = fragment.appendToPath(currentPath); currentPath = fragment.appendToPath(currentPath);
if (fragment.isArrayIndex()) { if (fragment.isArrayIndex()) {
current = toArray(current).get(fragment.getArrayIndex()); current = toArray(current).get(fragment.getArrayIndex());
} else if (fragment.isArrayWildcard()) { } else if (fragment.isArrayWildcard()) {
current = getContainerValue(current, path.nextFragment()); current = getContainerValue(current, path.poll());
} else { } else {
current = getContainerValue(current, fragment); current = getContainerValue(current, fragment);
} }
} }
return clazz.cast(current); return clazz.cast(current);
} }
*/
///*
private <T> T getByPath(Class<T> clazz, String stringPath) {
currentPath = "";
Object current = this.root;
Path path = new Path(stringPath);
while (path.hasMoreFragments()) {
PathFragment fragment = path.poll();
currentPath = fragment.appendToPath(currentPath);
if (fragment.isArrayIndex()) {
current = toArray(current).get(fragment.getArrayIndex());
} else if (fragment.isArrayWildcard()) {
current = getContainerValue(current, path.poll());
} else {
System.out.println("FRAGMENT " + fragment.toString());
current = getContainerValue(current, fragment);
if (isArray(current) && path.hasMoreFragments() && !path.peek().isArrayIndex() && !path.peek().isArrayWildcard()) {
JSONArray array = new JSONArray();
for (Object o : toArray(current)) {
String newPath = path.toString();
System.out.println("NEW PATH " + newPath);
if (isDocument(o) || isArray(o)) {
JsonReaderImpl sub = new JsonReaderImpl(o);
Object o1 = sub.get(newPath);
//if(o instanceof Collection){
array.add(o1);
//}
//else {
// array.addAll(l)
//}
} else {
System.out.println("hhhhhhh");
array.add(o);
}
}
current = array;
break;
}
}
}
return clazz.cast(current);
}
//*/
private boolean isArray(Object obj) {
return (obj instanceof JSONArray);
}
private boolean isDocument(Object obj) {
return (obj instanceof JSONObject);
}
private JSONArray toArray(Object array) { private JSONArray toArray(Object array) {
return (JSONArray) array; return (JSONArray) array;
@ -167,14 +248,14 @@ public class JSONReaderImpl implements JSONReader {
* will be returned in a List * will be returned in a List
* *
* @param container a json document or array * @param container a json document or array
* @param fragment the field to extract from the document alt. the documents contained in the array * @param fragment the field to extract from the document alt. the documents contained in the array
* @return a single field value or a List of fields * @return a single field value or a List of fields
*/ */
private Object getContainerValue(Object container, JSONPathFragment fragment) { private Object getContainerValue(Object container, PathFragment fragment) {
Object result; Object result;
if (container instanceof JSONArray) { if (container instanceof JSONArray) {
List list = new LinkedList(); List<Object> list = new LinkedList<Object>();
for (Object doc : toArray(container)) { for (Object doc : toArray(container)) {
list.add(getContainerValue(doc, fragment)); list.add(getContainerValue(doc, fragment));
} }

185
json-assert/src/main/java/com/jayway/jsonassert/impl/JsonPathImpl.java

@ -0,0 +1,185 @@
package com.jayway.jsonassert.impl;
import com.jayway.jsonassert.InvalidPathException;
import com.jayway.jsonassert.JsonPath;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import java.util.Map;
/**
* User: kalle stenflo
* Date: 2/1/11
* Time: 8:45 AM
*
* http://goessner.net/articles/JsonPath/
*/
public class JsonPathImpl implements JsonPath {
private static final JSONParser JSON_PARSER = new JSONParser();
private Object model;
public static synchronized JsonPath parse(Reader reader) throws java.text.ParseException, IOException {
try {
return new JsonPathImpl(JSON_PARSER.parse(reader));
} catch (IOException e) {
throw e;
} catch (ParseException e) {
throw new java.text.ParseException(e.getMessage(), e.getPosition());
}
}
public static synchronized JsonPath parse(String jsonDoc) throws java.text.ParseException {
try {
return new JsonPathImpl(JSON_PARSER.parse(jsonDoc));
} catch (ParseException e) {
throw new java.text.ParseException(e.getMessage(), e.getPosition());
}
}
public JsonPathImpl(Object model) {
this.model = model;
}
private void read(Object root, Path path, ReaderContext ctx, boolean strict) {
if (!path.hasMoreFragments()) {
ctx.addResult(root);
return;
}
if (isDocument(root)) {
PathFragment fragment = path.poll();
if(strict && !toDocument(root).containsKey(fragment.value())){
throw new InvalidPathException();
}
Object extracted = toDocument(root).get(fragment.value());
if (fragment.isLeaf()) {
ctx.addResult(extracted);
} else {
read(extracted, path.clone(), ctx, strict);
}
} else {
PathFragment fragment = path.poll();
if (fragment.isArrayIndex()) {
Object extracted = toArray(root).get(fragment.getArrayIndex());
read(extracted, path.clone(), ctx, strict);
} else if (fragment.isArrayWildcard()) {
ctx.split();
for (Object extracted : toArray(root)) {
read(extracted, path.clone(), ctx, strict);
}
}
}
}
private static class ReaderContext {
private JSONArray result = new JSONArray();
private boolean pathSplit = false;
private void addResult(Object obj) {
result.add(obj);
}
private void split() {
pathSplit = true;
}
private boolean isPathSplit() {
return pathSplit;
}
}
private <T> T get(String jsonPath, boolean strict) {
Path path = new Path(jsonPath);
ReaderContext ctx = new ReaderContext();
read(model, path.clone(), ctx, strict);
if (ctx.isPathSplit()) {
return (T) ctx.result;
} else {
return (T) ctx.result.get(0);
}
}
public JsonPath getReader(String path) {
Object subModel = get(path);
if (!isArray(subModel) && !isDocument(subModel)) {
throw new InvalidPathException();
}
return new JsonPathImpl(subModel);
}
public boolean hasJsonPath(String path) {
boolean hasPath = true;
try {
get(path, true);
} catch (Exception e) {
hasPath = false;
}
return hasPath;
}
public boolean isNull(String path) {
return (get(path) == null);
}
public <T> T get(String jsonPath) {
return (T) get(jsonPath, false);
}
public String getString(String path) {
return get(path);
}
public Long getLong(String path) {
return get(path);
}
public Double getDouble(String path) {
return get(path);
}
public Boolean getBoolean(String path) {
return get(path);
}
public <T> List<T> getList(String path) {
return get(path);
}
public Map<String, Object> getMap(String path) {
return get(path);
}
private boolean isArray(Object obj) {
return (obj instanceof JSONArray);
}
private boolean isDocument(Object obj) {
return (obj instanceof JSONObject);
}
private JSONArray toArray(Object array) {
return (JSONArray) array;
}
private JSONObject toDocument(Object document) {
return (JSONObject) document;
}
}

72
json-assert/src/main/java/com/jayway/jsonassert/impl/Path.java

@ -0,0 +1,72 @@
package com.jayway.jsonassert.impl;
import java.util.LinkedList;
import java.util.Queue;
/**
* User: kalle stenflo
* Date: 1/23/11
* Time: 1:52 PM
*/
class Path {
private final Queue<PathFragment> path;
Path(String path) {
this.path = compilePathFragments(path);
}
Path(Queue<PathFragment> path) {
this.path = new LinkedList<PathFragment>();
this.path.addAll(path);
}
int size() {
return path.size();
}
boolean hasMoreFragments() {
return !path.isEmpty();
}
PathFragment poll() {
return path.poll();
}
PathFragment peek() {
return path.peek();
}
@Override
protected Path clone() {
return new Path(path);
}
@Override
public String toString() {
String result = "";
for (PathFragment fragment : path) {
result = fragment.appendToPath(result);
}
return result;
}
private Queue<PathFragment> compilePathFragments(String path) {
//TODO: this needs some attention but will work for now
Queue<PathFragment> processed = new LinkedList<PathFragment>();
String[] split = path.split("[\\.|\\[]");
for (int i = 0; i < split.length; i++) {
if (split[i].trim().length() > 0) {
String compiledFragment = split[i].endsWith("]") ? "[" + split[i] : split[i];
boolean isLeaf = (i == split.length - 1);
processed.add(new PathFragment(compiledFragment, isLeaf));
}
}
return processed;
}
}

122
json-assert/src/main/java/com/jayway/jsonassert/impl/PathFragment.java

@ -0,0 +1,122 @@
package com.jayway.jsonassert.impl;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* User: kalle stenflo
* Date: 1/23/11
* Time: 1:55 PM
*/
class PathFragment {
//matches array index accessers like : [1], [23]
private static final Pattern ARRAY_POSITION_PATTER = Pattern.compile("\\[(\\d*)\\]");
//matches groovy style array index accessers like : get(1), get(23)
private static final Pattern GROOVY_POSITION_PATTER = Pattern.compile("get\\((\\d*)\\)");
//matches array wildcard : [*]
private static final Pattern ARRAY_WILDCARD_PATTER = Pattern.compile("\\[\\*\\]");
//matches groovy style array wildcard : [*]
private static final Pattern GROOVY_WILDCARD_PATTER = Pattern.compile("get\\(\\*\\)");
private final String value;
private final boolean leaf;
/**
* Creates a new path fragment
*
* @param value value of path fragment
* @param leaf
*/
PathFragment(String value, boolean leaf) {
this.value = value;
this.leaf = leaf;
}
@Override
public String toString() {
return "JSONPathFragment{" +
"value='" + value + '\'' +
'}';
}
/**
*
* @return the value of this path fragment
*/
String value() {
return value;
}
/**
* Utility method to rebuild a path from path fragments
*
* @param path the path to append this path fragment to
*
* @return the new extended path
*/
String appendToPath(String path){
StringBuilder builder = new StringBuilder(path);
if(ARRAY_POSITION_PATTER.matcher(value).matches()){
builder.append("[").append(getArrayIndex()).append("]");
}
else if(GROOVY_POSITION_PATTER.matcher(value).matches()){
builder.append(path.isEmpty()?"":".").append("get(").append(getArrayIndex()).append(")");
}
else if(ARRAY_WILDCARD_PATTER.matcher(value).matches()){
builder.append("[*]");
}
else if(GROOVY_WILDCARD_PATTER.matcher(value).matches()){
builder.append(path.isEmpty()?"":".").append("get(*)");
}
else {
builder.append(path.isEmpty()?"":".").append(value);
}
return builder.toString();
}
boolean isLeaf(){
return leaf;
}
/**
* Check if this path fragment is a array index
*
* @return true if this fragment is an array index
*/
boolean isArrayIndex() {
return ARRAY_POSITION_PATTER.matcher(value).matches() || GROOVY_POSITION_PATTER.matcher(value).matches();
}
/**
* Check if this path fragment is an array wildcard
*
* @return true if this fragment is an array wildcard
*/
boolean isArrayWildcard() {
return ARRAY_WILDCARD_PATTER.matcher(value).matches() || GROOVY_WILDCARD_PATTER.matcher(value).matches();
}
/**
* returns the int index of this path fragment. If this is not an array index fragment
* an UnsupportedOperationException is thrown
*
* @return the array index of this fragment
*/
int getArrayIndex() {
Matcher matcher = ARRAY_POSITION_PATTER.matcher(value);
if (matcher.matches()) {
return Integer.parseInt(matcher.group(1));
}
matcher = GROOVY_POSITION_PATTER.matcher(value);
if (matcher.matches()) {
return Integer.parseInt(matcher.group(1));
}
throw new UnsupportedOperationException("not an array index fragment");
}
}

18
json-assert/src/test/java/com/jayway/jsonassert/JSONAssertTest.java

@ -9,7 +9,7 @@ import static org.hamcrest.Matchers.*;
* Date: 1/21/11 * Date: 1/21/11
* Time: 4:04 PM * Time: 4:04 PM
*/ */
public class JSONAssertTest { public class JsonAssertTest {
private static String TEST_DOCUMENT = "{ \"nullField\" : null \"stringField\" : \"string-field\" , \"numberField\" : 1234 , \"booleanField\" : true , \"subDocument\" : {\"subField\" : \"sub-field\"} , \"stringList\" : [\"ONE\", \"TWO\"], \"objectList\" : [{\"subField\" : \"sub-field-0\"}, {\"subField\" : \"sub-field-1\"}], \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }"; private static String TEST_DOCUMENT = "{ \"nullField\" : null \"stringField\" : \"string-field\" , \"numberField\" : 1234 , \"booleanField\" : true , \"subDocument\" : {\"subField\" : \"sub-field\"} , \"stringList\" : [\"ONE\", \"TWO\"], \"objectList\" : [{\"subField\" : \"sub-field-0\"}, {\"subField\" : \"sub-field-1\"}], \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }";
@ -17,48 +17,48 @@ public class JSONAssertTest {
@Test @Test
public void a_path_can_be_asserted_with_matcher() throws Exception { public void a_path_can_be_asserted_with_matcher() throws Exception {
JSONAssert.with(TEST_DOCUMENT).assertThat("stringField", equalTo("string-field")); JsonAssert.with(TEST_DOCUMENT).assertThat("stringField", equalTo("string-field"));
} }
@Test @Test
public void list_content_can_be_asserted_with_matcher() throws Exception { public void list_content_can_be_asserted_with_matcher() throws Exception {
JSONAssert.with(TEST_DOCUMENT).assertThat("stringList", hasItems("ONE", "TWO")); JsonAssert.with(TEST_DOCUMENT).assertThat("stringList", hasItems("ONE", "TWO"));
} }
@Test @Test
public void map_content_can_be_asserted_with_matcher() throws Exception { public void map_content_can_be_asserted_with_matcher() throws Exception {
JSONAssert.with(TEST_DOCUMENT).assertThat("subDocument", hasEntry("subField", "sub-field")); JsonAssert.with(TEST_DOCUMENT).assertThat("subDocument", hasEntry("subField", "sub-field"));
} }
@Test @Test
public void a_sub_document_can_asserted_on__by_path() throws Exception { public void a_sub_document_can_asserted_on__by_path() throws Exception {
JSONAssert.with(TEST_DOCUMENT).assertThat("subDocument.subField", is(equalTo("sub-field"))); JsonAssert.with(TEST_DOCUMENT).assertThat("subDocument.subField", is(equalTo("sub-field")));
} }
@Test @Test
public void a_path_can_be_asserted_equal_to() throws Exception { public void a_path_can_be_asserted_equal_to() throws Exception {
JSONAssert.with(TEST_DOCUMENT).assertEquals("stringField", "string-field"); JsonAssert.with(TEST_DOCUMENT).assertEquals("stringField", "string-field");
} }
@Test @Test
public void a_path_can_be_asserted_is_null() throws Exception { public void a_path_can_be_asserted_is_null() throws Exception {
JSONAssert.with(TEST_DOCUMENT).assertNull("nullField"); JsonAssert.with(TEST_DOCUMENT).assertNull("nullField");
} }
@Test(expected = AssertionError.class) @Test(expected = AssertionError.class)
public void failed_assert_throws() throws Exception { public void failed_assert_throws() throws Exception {
JSONAssert.with(TEST_DOCUMENT).assertThat("stringField", equalTo("SOME CRAP")); JsonAssert.with(TEST_DOCUMENT).assertThat("stringField", equalTo("SOME CRAP"));
} }
@Test @Test
public void multiple_asserts_can_be_chained() throws Exception { public void multiple_asserts_can_be_chained() throws Exception {
JSONAssert.with(TEST_DOCUMENT) JsonAssert.with(TEST_DOCUMENT)
.assertThat("stringField", equalTo("string-field")) .assertThat("stringField", equalTo("string-field"))
.assertThat("numberField", is(notNullValue())) .assertThat("numberField", is(notNullValue()))
.and() .and()

157
json-assert/src/test/java/com/jayway/jsonassert/JSONReaderTest.java

@ -1,13 +1,13 @@
package com.jayway.jsonassert; package com.jayway.jsonassert;
import com.jayway.jsonassert.impl.JSONReaderImpl; import com.jayway.jsonassert.impl.JsonReaderImpl;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Test; import org.junit.Test;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.text.ParseException; import java.text.ParseException;
import java.util.List; import java.util.List;
import java.util.Map;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -16,48 +16,56 @@ import static org.junit.Assert.*;
* Date: 1/20/11 * Date: 1/20/11
* Time: 9:31 AM * Time: 9:31 AM
*/ */
public class JSONReaderTest { public class JsonReaderTest {
private static String TEST_DOCUMENT = "{ \"nullField\" : null \"stringField\" : \"string-field\" , \"numberField\" : 1234 , \"doubleField\" : 12.34 , \"booleanField\" : true , \"subDocument\" : {\"subField\" : \"sub-field\"} , \"stringList\" : [\"ONE\", \"TWO\"], \"objectList\" : [{\"subField\" : \"sub-field-0\"}, {\"subField\" : \"sub-field-1\"}], \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }"; private static String TEST_DOCUMENT = "{ \"nullField\" : null, \"stringField\" : \"string-field\" , \"numberField\" : 1234 , \"doubleField\" : 12.34 , \"booleanField\" : true , \"subDocument\" : {\"subField\" : \"sub-field\"} , \"stringList\" : [\"ONE\", \"TWO\"], \"objectList\" : [{\"subField\" : \"sub-field-0\", \"subDoc\": {\"subField\": \"A\"}}, {\"subField\" : \"sub-field-1\", \"subDoc\": {\"subField\": \"B\"}}], \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }";
private static String TEST_DOCUMENT_ARRAY = "{ \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }"; private static String TEST_DOCUMENT_ARRAY = "{ \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }";
private static String TEST_DEEP_PATH_DOCUMENT = "{ \"a\" : { \"b\" : { \"c\" : { \"say\" : \"hello\" } } }}"; private static String TEST_DEEP_PATH_DOCUMENT = "{ \"a\" : { \"b\" : { \"c\" : { \"say\" : \"hello\" } } }}";
private static String TEST_ARRAY = "[{\"name\" : \"name0\"}, {\"name\" : \"name1\"}]"; private static String TEST_ARRAY = "[{\"name\" : \"name0\"}, {\"name\" : \"name1\"}]";
private static String TEST_DEEP_PATH_DOCUMENT_ARRAY = "{ \"arr0\" : [{ \"arr0_0\" : [{ \"arr0_0_0\" : [{\"val\": \"0A\"}, {\"val\": \"1A\"}] }, { \"arr0_0\" : [{ \"arr0_0_0\" : [{\"val\": \"1A\"}, {\"val\": \"1B\"}] }] } ] }";
@Test(expected = ParseException.class) @Test(expected = ParseException.class)
public void invalid_json_not_accepted() throws Exception { public void invalid_json_not_accepted() throws Exception {
JSONReaderImpl.parse("not json"); JsonReaderImpl.parse("not json");
} }
@Test @Test
public void reader_can_be_created_with_input_stream() throws Exception { public void reader_can_be_created_with_input_stream() throws Exception {
JSONReader reader = JSONAssert.parse(getInputStreamReader("json-test-doc.json"), true); JsonPath reader = JsonAssert.parse(getInputStreamReader("json-test-doc.json"), true);
assertEquals("donut", reader.getString("type")); assertEquals("donut", reader.getString("type"));
assertEquals("donut", reader.get("type"));
assertThat(reader.<String>getList("toppings"), Matchers.hasItems("Glazed", "Sugar")); assertThat(reader.<String>getList("toppings"), Matchers.hasItems("Glazed", "Sugar"));
assertThat(reader.<List<String>>get("toppings"), Matchers.hasItems("Glazed", "Sugar"));
} }
@Test @Test
public void a_string_field_can_be_accessed() throws Exception { public void a_string_field_can_be_accessed() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("string-field", reader.getString("stringField")); assertEquals("string-field", reader.getString("stringField"));
assertEquals("string-field", reader.get("stringField"));
} }
@Test @Test
public void is_null_returns_true_for_null_fields() throws Exception { public void is_null_returns_true_for_null_fields() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertTrue(reader.isNull("nullField")); assertTrue(reader.isNull("nullField"));
} }
@Test @Test
public void is_null_returns_false_for_not_null_fields() throws Exception { public void is_null_returns_false_for_not_null_fields() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertFalse(reader.isNull("stringField")); assertFalse(reader.isNull("stringField"));
} }
@ -65,183 +73,222 @@ public class JSONReaderTest {
@Test @Test
public void a_long_field_can_be_accessed() throws Exception { public void a_long_field_can_be_accessed() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertTrue(1234L == reader.getLong("numberField")); assertTrue(1234L == reader.getLong("numberField"));
assertEquals(1234L, reader.get("numberField"));
} }
@Test @Test
public void a_double_field_can_be_accessed() throws Exception { public void a_double_field_can_be_accessed() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals(12.34D, reader.getDouble("doubleField"), 0.001); assertEquals(12.34D, reader.getDouble("doubleField"), 0.001);
assertEquals(12.34D, reader.<Double>get("doubleField"), 0.001);
} }
@Test @Test
public void a_boolean_field_can_be_accessed() throws Exception { public void a_boolean_field_can_be_accessed() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals(true, reader.getBoolean("booleanField")); assertEquals(true, reader.getBoolean("booleanField"));
assertEquals(true, reader.get("booleanField"));
} }
@Test @Test
public void a_path_can_be_checked_for_existence() throws Exception { public void a_path_can_be_checked_for_existence() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DEEP_PATH_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DEEP_PATH_DOCUMENT);
assertTrue(reader.hasJsonPath("a.b.c.say")); assertTrue(reader.hasJsonPath("a.b.c.say"));
} }
@Test @Test
public void a_path_can_be_checked_for_non_existence() throws Exception { public void a_path_can_be_checked_for_non_existence() throws Exception {
JsonPath reader = JsonAssert.parse(TEST_DEEP_PATH_DOCUMENT);
JSONReader reader = JSONAssert.parse(TEST_DEEP_PATH_DOCUMENT);
assertFalse(reader.hasJsonPath("a.b.c.FOO")); assertFalse(reader.hasJsonPath("a.b.c.FOO"));
} }
@Test @Test
public void a_string_field_can_be_accessed_in_a_nested_document() throws Exception { public void a_string_field_can_be_accessed_in_a_nested_document() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("sub-field", reader.getString("subDocument.subField")); assertEquals("sub-field", reader.getString("subDocument.subField"));
assertEquals("sub-field", reader.get("subDocument.subField"));
} }
@Test @Test
public void a_list_can_be_accessed_in_a_document() throws Exception { public void a_list_can_be_accessed_in_a_document() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
List<String> l = reader.<String>getList("stringList");
assertEquals(2, l.size()); assertEquals(2, reader.<String>getList("stringList").size());
assertEquals(2, reader.<List<String>>get("stringList").size());
} }
@Test @Test
public void a_list_can_be_accessed_by_array_index() throws Exception { public void a_list_can_be_accessed_by_array_index() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("ONE", reader.getString("stringList[0]")); assertEquals("ONE", reader.getString("stringList[0]"));
assertEquals("TWO", reader.getString("stringList[1]")); assertEquals("TWO", reader.getString("stringList[1]"));
assertEquals("ONE", reader.get("stringList[0]"));
assertEquals("TWO", reader.get("stringList[1]"));
} }
@Test @Test
public void a_list_can_be_accessed_by_groovy_index() throws Exception { public void a_list_can_be_accessed_by_groovy_index() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("ONE", reader.getString("stringList.get(0)")); assertEquals("ONE", reader.getString("stringList.get(0)"));
assertEquals("TWO", reader.getString("stringList.get(1)")); assertEquals("TWO", reader.getString("stringList.get(1)"));
assertEquals("ONE", reader.get("stringList.get(0)"));
assertEquals("TWO", reader.get("stringList.get(1)"));
} }
@Test @Test
public void a_document_contained_in_a_list_can_be_accessed_by_array_index() throws Exception { public void a_document_contained_in_a_list_can_be_accessed_by_array_index() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("sub-field-0", reader.getString("objectList[0].subField")); assertEquals("sub-field-0", reader.getString("objectList[0].subField"));
assertEquals("sub-field-0", reader.get("objectList[0].subField"));
} }
@Test @Test
public void a_document_contained_in_a_list_can_be_accessed_by_groovy_index() throws Exception { public void a_document_contained_in_a_list_can_be_accessed_by_groovy_index() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("sub-field-0", reader.getString("objectList.get(0).subField")); assertEquals("sub-field-0", reader.getString("objectList.get(0).subField"));
assertEquals("sub-field-0", reader.get("objectList.get(0).subField"));
} }
@Test @Test
public void an_array_in_an_array_can_be_accessed_by_array_index() throws Exception { public void an_array_in_an_array_can_be_accessed_by_array_index() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT_ARRAY); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT_ARRAY);
assertEquals("0.0", reader.getString("listList[0][0]")); assertEquals("0.0", reader.getString("listList[0][0]"));
assertEquals("0.1", reader.getString("listList[0][1]")); assertEquals("0.1", reader.getString("listList[0][1]"));
assertEquals("1.0", reader.getString("listList[1][0]")); assertEquals("1.0", reader.getString("listList[1][0]"));
assertEquals("1.1", reader.getString("listList[1][1]")); assertEquals("1.1", reader.getString("listList[1][1]"));
assertEquals("0.0", reader.get("listList[0][0]"));
assertEquals("0.1", reader.get("listList[0][1]"));
assertEquals("1.0", reader.get("listList[1][0]"));
assertEquals("1.1", reader.get("listList[1][1]"));
} }
@Test @Test
public void an_array_in_an_array_can_be_accessed_by_groovy_index() throws Exception { public void an_array_in_an_array_can_be_accessed_by_groovy_index() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT_ARRAY); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT_ARRAY);
assertEquals("0.0", reader.getString("listList.get(0).get(0)")); assertEquals("0.0", reader.getString("listList.get(0).get(0)"));
assertEquals("0.1", reader.getString("listList.get(0).get(1)")); assertEquals("0.1", reader.getString("listList.get(0).get(1)"));
assertEquals("1.0", reader.getString("listList.get(1).get(0)")); assertEquals("1.0", reader.getString("listList.get(1).get(0)"));
assertEquals("1.1", reader.getString("listList.get(1).get(1)")); assertEquals("1.1", reader.getString("listList.get(1).get(1)"));
assertEquals("0.0", reader.get("listList.get(0).get(0)"));
assertEquals("0.1", reader.get("listList.get(0).get(1)"));
assertEquals("1.0", reader.get("listList.get(1).get(0)"));
assertEquals("1.1", reader.get("listList.get(1).get(1)"));
} }
@Test @Test
public void an_array_with_documents_can_be_accessed_by_index() throws Exception { public void an_array_with_documents_can_be_accessed_by_index() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_ARRAY); JsonPath reader = JsonAssert.parse(TEST_ARRAY);
assertEquals("name0", reader.getString("[0].name")); assertEquals("name0", reader.getString("[0].name"));
assertEquals("name1", reader.getString("[1].name")); assertEquals("name1", reader.getString("[1].name"));
assertEquals("name0", reader.get("[0].name"));
assertEquals("name1", reader.get("[1].name"));
} }
@Test @Test
public void a_nested_document_can_be_accessed_as_a_map() throws Exception { public void a_nested_document_can_be_accessed_as_a_map() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("sub-field", reader.getMap("subDocument").get("subField")); assertEquals("sub-field", reader.getMap("subDocument").get("subField"));
}
@Test assertEquals("sub-field", reader.<Map>get("subDocument").get("subField"));
public void every_thing_can_be_fetched_as_object() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT);
assertEquals(true, reader.get("booleanField"));
assertEquals(1234L, reader.get("numberField"));
assertEquals("string-field", reader.get("stringField"));
} }
@Test @Test
public void a_deep_document_path_can_be_read() throws Exception { public void a_deep_document_path_can_be_read() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DEEP_PATH_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DEEP_PATH_DOCUMENT);
assertEquals("hello", reader.getString("a.b.c.say")); assertEquals("hello", reader.getString("a.b.c.say"));
assertEquals("hello", reader.get("a.b.c.say"));
} }
@Test(expected = InvalidPathException.class) @Test(expected = InvalidPathException.class)
public void exception_is_thrown_when_field_is_not_found() throws Exception { public void exception_is_thrown_when_field_is_not_found() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
String s = reader.getString("invalidProperty"); reader.getString("invalidProperty");
}
System.out.println("S= " + s); @Test(expected = InvalidPathException.class)
public void exception_is_thrown_when_field_is_not_found_with_get() throws Exception {
JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
reader.get("invalidProperty");
} }
@Test @Test
public void array_wildcard_property_extract() throws Exception { public void array_wildcard_property_extract() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
List<String> l = reader.<String>getList("objectList[*].subField"); assertEquals(2, reader.<String>getList("objectList[*].subField").size());
assertEquals(2, l.size()); assertEquals(2, reader.<List<String>>get("objectList[*].subField").size());
/*
assertEquals(2, reader.getList("objectList[*.subField]").size()); }
@Test
public void array_wildcard_property_extract_new() throws Exception {
JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals(2, reader.getList("objectList[subField='foo']").size()); assertEquals("A", reader.<String>getList("objectList.subDoc.subField").get(0));
assertEquals("B", reader.<String>getList("objectList.subDoc.subField").get(1));
assertEquals(2, reader.getList("objectList[].subField#foo").size()); assertEquals("A", reader.<List<String>>get("objectList.subDoc.subField").get(0));
assertEquals("B", reader.<List<String>>get("objectList.subDoc.subField").get(1));
*/
} }
@Test @Test
public void list_to_string_returns_json() throws Exception { public void list_to_string_returns_json() throws Exception {
JSONReader reader = JSONAssert.parse(TEST_DOCUMENT); JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("[\"ONE\",\"TWO\"]", reader.getList("stringList").toString()); assertEquals("[\"ONE\",\"TWO\"]", reader.getList("stringList").toString());
} }
@Test
public void get_sub_reader_for_document() throws Exception {
JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("sub-field", reader.getReader("subDocument").getString("subField"));
}
@Test
public void get_sub_reader_for_list() throws Exception {
JsonPath reader = JsonAssert.parse(TEST_DOCUMENT);
assertEquals("ONE", reader.getReader("stringList").get("[0]"));
}
//---------------------------------------------------------- //----------------------------------------------------------
// //
// helpers // helpers

278
json-assert/src/test/java/com/jayway/jsonassert/JsonPathTest.java

@ -0,0 +1,278 @@
package com.jayway.jsonassert;
import com.jayway.jsonassert.impl.JsonPathImpl;
import org.junit.Test;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
/**
* Created by IntelliJ IDEA.
* User: kallestenflo
* Date: 2/1/11
* Time: 10:08 AM
*/
public class JsonPathTest {
private static String TEST_DOCUMENT = "{ \"nullField\" : null, \"stringField\" : \"string-field\" , \"numberField\" : 1234 , \"doubleField\" : 12.34 , \"booleanField\" : true , \"subDocument\" : {\"subField\" : \"sub-field\"} , \"stringList\" : [\"ONE\", \"TWO\"], \"objectList\" : [{\"subField\" : \"sub-field-0\", \"subDoc\": {\"subField\": \"A\"}}, {\"subField\" : \"sub-field-1\", \"subDoc\": {\"subField\": \"B\"}}], \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }";
private static String TEST_DOCUMENT_ARRAY = "{ \"listList\" : [[\"0.0\", \"0.1\"], [\"1.0\", \"1.1\"]], }";
private static String TEST_DEEP_PATH_DOCUMENT = "{ \"a\" : { \"b\" : { \"c\" : { \"say\" : \"hello\" } } }}";
private static String TEST_ARRAY = "[{\"name\" : \"name0\"}, {\"name\" : \"name1\"}]";
private static String TEST_DEEP_PATH_DOCUMENT_ARRAY = "{ \"arr0\" : [{ \"arr0_0\" : [{ \"arr0_0_0\" : [{\"val\": \"0A\"}, {\"val\": \"1A\"}] }, { \"arr0_0\" : [{ \"arr0_0_0\" : [{\"val\": \"1A\"}, {\"val\": \"1B\"}] }] } ] }";
@Test
public void a_string_field_can_be_accessed() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("string-field", reader.getString("stringField"));
assertEquals("string-field", reader.get("stringField"));
}
@Test
public void is_null_returns_true_for_null_fields() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertTrue(reader.isNull("nullField"));
}
@Test
public void is_null_returns_false_for_not_null_fields() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertFalse(reader.isNull("stringField"));
}
@Test
public void a_long_field_can_be_accessed() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertTrue(1234L == reader.getLong("numberField"));
assertEquals(1234L, reader.get("numberField"));
}
@Test
public void a_double_field_can_be_accessed() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals(12.34D, reader.getDouble("doubleField"), 0.001);
assertEquals(12.34D, reader.<Double>get("doubleField"), 0.001);
}
@Test
public void a_boolean_field_can_be_accessed() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals(true, reader.getBoolean("booleanField"));
assertEquals(true, reader.get("booleanField"));
}
@Test
public void a_path_can_be_checked_for_existence() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DEEP_PATH_DOCUMENT);
assertTrue(reader.hasJsonPath("a.b.c.say"));
}
@Test
public void a_path_can_be_checked_for_non_existence() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DEEP_PATH_DOCUMENT);
assertFalse(reader.hasJsonPath("a.b.c.FOO"));
}
@Test
public void a_string_field_can_be_accessed_in_a_nested_document() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("sub-field", reader.getString("subDocument.subField"));
assertEquals("sub-field", reader.get("subDocument.subField"));
}
@Test
public void a_list_can_be_accessed_in_a_document() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals(2, reader.<String>getList("stringList").size());
assertEquals(2, reader.<List<String>>get("stringList").size());
}
@Test
public void a_list_can_be_accessed_by_array_index() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("ONE", reader.getString("stringList[0]"));
assertEquals("TWO", reader.getString("stringList[1]"));
assertEquals("ONE", reader.get("stringList[0]"));
assertEquals("TWO", reader.get("stringList[1]"));
}
@Test
public void a_list_can_be_accessed_by_groovy_index() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("ONE", reader.getString("stringList.get(0)"));
assertEquals("TWO", reader.getString("stringList.get(1)"));
assertEquals("ONE", reader.get("stringList.get(0)"));
assertEquals("TWO", reader.get("stringList.get(1)"));
}
@Test
public void a_document_contained_in_a_list_can_be_accessed_by_array_index() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("sub-field-0", reader.getString("objectList[0].subField"));
assertEquals("sub-field-0", reader.get("objectList[0].subField"));
}
@Test
public void a_document_contained_in_a_list_can_be_accessed_by_groovy_index() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("sub-field-0", reader.getString("objectList.get(0).subField"));
assertEquals("sub-field-0", reader.get("objectList.get(0).subField"));
}
@Test
public void an_array_in_an_array_can_be_accessed_by_array_index() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT_ARRAY);
assertEquals("0.0", reader.getString("listList[0][0]"));
assertEquals("0.1", reader.getString("listList[0][1]"));
assertEquals("1.0", reader.getString("listList[1][0]"));
assertEquals("1.1", reader.getString("listList[1][1]"));
assertEquals("0.0", reader.get("listList[0][0]"));
assertEquals("0.1", reader.get("listList[0][1]"));
assertEquals("1.0", reader.get("listList[1][0]"));
assertEquals("1.1", reader.get("listList[1][1]"));
}
@Test
public void an_array_in_an_array_can_be_accessed_by_groovy_index() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT_ARRAY);
assertEquals("0.0", reader.getString("listList.get(0).get(0)"));
assertEquals("0.1", reader.getString("listList.get(0).get(1)"));
assertEquals("1.0", reader.getString("listList.get(1).get(0)"));
assertEquals("1.1", reader.getString("listList.get(1).get(1)"));
assertEquals("0.0", reader.get("listList.get(0).get(0)"));
assertEquals("0.1", reader.get("listList.get(0).get(1)"));
assertEquals("1.0", reader.get("listList.get(1).get(0)"));
assertEquals("1.1", reader.get("listList.get(1).get(1)"));
}
@Test
public void an_array_with_documents_can_be_accessed_by_index() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_ARRAY);
assertEquals("name0", reader.getString("[0].name"));
assertEquals("name1", reader.getString("[1].name"));
assertEquals("name0", reader.get("[0].name"));
assertEquals("name1", reader.get("[1].name"));
}
@Test
public void a_nested_document_can_be_accessed_as_a_map() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("sub-field", reader.getMap("subDocument").get("subField"));
assertEquals("sub-field", reader.<Map>get("subDocument").get("subField"));
}
@Test
public void a_deep_document_path_can_be_read() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DEEP_PATH_DOCUMENT);
assertEquals("hello", reader.getString("a.b.c.say"));
assertEquals("hello", reader.get("a.b.c.say"));
}
/*
@Test(expected = InvalidPathException.class)
public void exception_is_thrown_when_field_is_not_found() throws Exception {
JSONReader reader = JsonQueryNew.parse(TEST_DOCUMENT);
reader.getString("invalidProperty");
}
*/
@Test
public void null_is_returned_when_field_is_not_found() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertNull(reader.getString("invalidProperty"));
}
public void null_is_when_field_is_not_found_with_get() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertNull(reader.get("invalidProperty"));
}
@Test
public void array_wildcard_property_extract() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals(2, reader.<String>getList("objectList[*].subField").size());
assertEquals(2, reader.<List<String>>get("objectList[*].subField").size());
}
@Test
public void array_wildcard_property_extract_new() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("A", reader.<String>getList("objectList[*].subDoc.subField").get(0));
assertEquals("B", reader.<String>getList("objectList[*].subDoc.subField").get(1));
assertEquals("A", reader.<List<String>>get("objectList[*].subDoc.subField").get(0));
assertEquals("B", reader.<List<String>>get("objectList[*].subDoc.subField").get(1));
}
@Test
public void list_to_string_returns_json() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("[\"ONE\",\"TWO\"]", reader.getList("stringList").toString());
}
@Test
public void get_sub_reader_for_document() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("sub-field", reader.getReader("subDocument").getString("subField"));
}
@Test
public void get_sub_reader_for_list() throws Exception {
JsonPath reader = JsonPathImpl.parse(TEST_DOCUMENT);
assertEquals("ONE", reader.getReader("stringList").get("[0]"));
}
}

27
json-assert/src/test/resources/json_array.json

@ -0,0 +1,27 @@
{
"arr": [
{
"obj":{"innerArr": [
{
"val": "bla_0"
},
{
"val": null
}
]}
},
{
"obj":{"innerArr": [
{
"val": "bla_4"
},
{
"val": "bla_5"
}
]}
}
]
}

6
pom.xml

@ -130,6 +130,12 @@
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency>
<groupId>commons-jxpath</groupId>
<artifactId>commons-jxpath</artifactId>
<version>1.3</version>
</dependency>
<dependency> <dependency>
<groupId>com.googlecode.json-simple</groupId> <groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId> <artifactId>json-simple</artifactId>

Loading…
Cancel
Save