From d0a7d2f56489240f1b06fd1e710873965080cd29 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Fri, 12 Sep 2014 14:46:35 +0200 Subject: [PATCH] GsonProvider --- json-path/pom.xml | 6 + .../java/com/jayway/jsonpath/Criteria.java | 1 + .../java/com/jayway/jsonpath/ReadContext.java | 7 + .../jayway/jsonpath/internal/JsonReader.java | 5 + .../compiler/EvaluationContextImpl.java | 6 +- .../internal/compiler/PredicatePathToken.java | 2 +- .../internal/compiler/ScanPathToken.java | 2 +- .../spi/json/AbstractJsonProvider.java | 6 +- .../internal/spi/json/GsonProvider.java | 195 ++++++++++++++++++ .../jsonpath/spi/json/JsonProvider.java | 4 +- .../com/jayway/jsonpath/ReturnTypeTest.java | 8 +- pom.xml | 7 + system.properties | 2 +- 13 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonProvider.java diff --git a/json-path/pom.xml b/json-path/pom.xml index ede1decd..4d9d20b7 100644 --- a/json-path/pom.xml +++ b/json-path/pom.xml @@ -35,6 +35,12 @@ jackson-databind true + + com.google.code.gson + gson + true + + diff --git a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java index f998d912..93becbae 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java @@ -290,6 +290,7 @@ public class Criteria implements Predicate { } else { try { final Object actual = path.evaluate(ctx.target(), ctx.configuration()).getValue(); + return criteriaType.eval(expected, actual, ctx.configuration()); } catch (CompareException e) { return false; diff --git a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java index 9fb8c6a3..71812a67 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java @@ -16,6 +16,13 @@ package com.jayway.jsonpath; public interface ReadContext { + /** + * Returns the configuration used for reading + * + * @return an immutable configuration + */ + Configuration configuration(); + /** * Returns the JSON model that this context is reading * diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java index 526e12c6..394fcfd5 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java @@ -77,6 +77,11 @@ public class JsonReader implements ParseContext, ReadContext { return parse(is); } + @Override + public Configuration configuration() { + return configuration; + } + //------------------------------------------------ // // ReadContext impl diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/EvaluationContextImpl.java b/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/EvaluationContextImpl.java index f1a36f7b..6de8b956 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/EvaluationContextImpl.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/EvaluationContextImpl.java @@ -60,9 +60,9 @@ public class EvaluationContextImpl implements EvaluationContext { if(resultIndex == 0){ throw new PathNotFoundException("No results for path: " + path.toString()); } - return (T) jsonProvider().getArrayIndex(valueResult, 0); + return (T) jsonProvider().unwrap(jsonProvider().getArrayIndex(valueResult, 0)); } - return (T) valueResult; + return (T) jsonProvider().unwrap(valueResult); } @SuppressWarnings("unchecked") @@ -78,7 +78,7 @@ public class EvaluationContextImpl implements EvaluationContext { public List getPathList() { List res = new ArrayList(); if(resultIndex > 0){ - Iterable objects = configuration.getProvider().toIterable(pathResult); + Iterable objects = configuration.getProvider().toIterable(pathResult); for (Object o : objects) { res.add((String)o); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/PredicatePathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/PredicatePathToken.java index 8090430c..199e095f 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/PredicatePathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/PredicatePathToken.java @@ -44,7 +44,7 @@ public class PredicatePathToken extends PathToken { } } else if (ctx.jsonProvider().isArray(model)){ int idx = 0; - Iterable objects = ctx.jsonProvider().toIterable(model); + Iterable objects = ctx.jsonProvider().toIterable(model); for (Object idxModel : objects) { if (accept(idxModel, ctx.configuration())) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/ScanPathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/ScanPathToken.java index a8e1323d..f7270789 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/ScanPathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/compiler/ScanPathToken.java @@ -55,7 +55,7 @@ public class ScanPathToken extends PathToken { predicateMatches.put(currentPath, model); } - Iterable models = ctx.jsonProvider().toIterable(model); + Iterable models = ctx.jsonProvider().toIterable(model); int idx = 0; for (Object evalModel : models) { String evalPath = currentPath + "[" + idx + "]"; diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java index d43b98d4..5ba88a2a 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java @@ -23,6 +23,10 @@ import java.util.Map; public abstract class AbstractJsonProvider implements JsonProvider { + public Object unwrap(Object obj){ + return obj; + } + /** * checks if object is an array * @@ -135,7 +139,7 @@ public abstract class AbstractJsonProvider implements JsonProvider { * @return the entries for an array or the values for a map */ @SuppressWarnings("unchecked") - public Iterable toIterable(Object obj) { + public Iterable toIterable(Object obj) { if (isArray(obj)) return ((Iterable) obj); else diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonProvider.java new file mode 100644 index 00000000..898a99fe --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonProvider.java @@ -0,0 +1,195 @@ +package com.jayway.jsonpath.internal.spi.json; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; +import com.google.gson.internal.LazilyParsedNumber; +import com.jayway.jsonpath.InvalidJsonException; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class GsonProvider extends AbstractJsonProvider { + + private static final JsonParser parser = new JsonParser(); + private static final Gson gson = new Gson(); + + + public Object unwrap(Object o){ + if(o == null){ + return null; + } + if(!(o instanceof JsonElement)){ + return o; + } + + Object unwrapped = null; + + JsonElement e = (JsonElement) o; + + if(e.isJsonNull()) { + unwrapped = null; + } else if(e.isJsonPrimitive()){ + + JsonPrimitive p = e.getAsJsonPrimitive(); + if(p.isString()){ + unwrapped = p.getAsString(); + } else if(p.isBoolean()){ + unwrapped = p.getAsBoolean(); + } else if(p.isNumber()){ + Number n = p.getAsNumber(); + if(n instanceof LazilyParsedNumber){ + LazilyParsedNumber lpn = (LazilyParsedNumber) n; + BigDecimal bigDecimal = new BigDecimal(lpn.toString()); + if(bigDecimal.scale() <= 0){ + if(bigDecimal.compareTo(new BigDecimal(Integer.MAX_VALUE)) <= 0){ + unwrapped = bigDecimal.intValue(); + } else { + unwrapped = bigDecimal.longValue(); + } + } else { + if(bigDecimal.compareTo(new BigDecimal(Float.MAX_VALUE)) <= 0){ + unwrapped = bigDecimal.floatValue(); + } else { + unwrapped = bigDecimal.doubleValue(); + } + } + } else { + unwrapped = n; + } + } + } else { + unwrapped = o; + } + return unwrapped; + } + + @Override + public Object parse(String json) throws InvalidJsonException { + return parser.parse(json); + } + + @Override + public Object parse(Reader jsonReader) throws InvalidJsonException { + return parser.parse(jsonReader); + } + + @Override + public Object parse(InputStream jsonStream) throws InvalidJsonException { + return parser.parse(new InputStreamReader(jsonStream)); + } + + @Override + public String toJson(Object obj) { + return ((JsonElement)obj).toString(); + } + + @Override + public Object createMap() { + return new JsonObject(); + } + + @Override + public Object createArray() { + return new JsonArray(); + } + + @Override + public boolean isArray(Object obj) { + return (obj instanceof JsonArray); + } + + @Override + public Object getArrayIndex(Object obj, int idx) { + return toJsonArray(obj).get(idx); + } + + @Override + public Object getMapValue(Object obj, String key) { + Object o = toJsonObject(obj).get(key); + if(o == null){ + return UNDEFINED; + } else { + return o; + } + } + + @Override + public void setProperty(Object obj, Object key, Object value) { + if (isMap(obj)) + toJsonObject(obj).add(key.toString(), toJsonElement(value)); + else { + JsonArray array = toJsonArray(obj); + int index; + if (key != null) { + index = key instanceof Integer ? (Integer) key : Integer.parseInt(key.toString()); + } else { + index = array.size(); + } + if(index == array.size()){ + array.add(toJsonElement(value)); + } else { + array.set(index, toJsonElement(value)); + } + + } + } + + @Override + public boolean isMap(Object obj) { + return (obj instanceof JsonObject); + } + + @Override + public Collection getPropertyKeys(Object obj) { + List keys = new ArrayList(); + for (Map.Entry entry : toJsonObject(obj).entrySet()) { + keys.add(entry.getKey()); + } + return keys; + } + + @Override + public int length(Object obj) { + if (isArray(obj)) { + return toJsonArray(obj).size(); + } else { + return toJsonObject(obj).entrySet().size(); + } + } + + @Override + public Iterable toIterable(Object obj) { + if (isArray(obj)) { + return toJsonArray(obj); + } else { + List values = new ArrayList(); + JsonObject jsonObject = toJsonObject(obj); + for (Map.Entry entry : jsonObject.entrySet()) { + values.add(entry.getValue()); + } + return values; + } + } + + private JsonElement toJsonElement(Object o){ + return gson.toJsonTree(o); + } + + private JsonArray toJsonArray(Object o){ + return (JsonArray) o; + } + + private JsonObject toJsonObject(Object o){ + return (JsonObject) o; + } +} diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java index 67ca5ed6..534a9967 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java @@ -24,6 +24,8 @@ public interface JsonProvider { static final Object UNDEFINED = new Object(); + public Object unwrap(Object obj); + Object parse(String json) throws InvalidJsonException; Object parse(Reader jsonReader) throws InvalidJsonException; @@ -58,7 +60,7 @@ public interface JsonProvider { * @param obj an array or an object * @return the entries for an array or the values for a map */ - Iterable toIterable(Object obj); + Iterable toIterable(Object obj); /** diff --git a/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java b/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java index 8a6bc601..d749bade 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java @@ -2,7 +2,6 @@ package com.jayway.jsonpath; import org.junit.Test; -import java.util.List; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; @@ -39,7 +38,12 @@ public class ReturnTypeTest extends BaseTest { @Test public void assert_arrays_can_be_read() { - assertThat(reader.read("$.store.book", List.class)).hasSize(4); + + Object result = reader.read("$.store.book"); + + assertThat(reader.configuration().getProvider().isArray(result)).isTrue(); + + assertThat(reader.configuration().getProvider().length(result)).isEqualTo(4); } @Test diff --git a/pom.xml b/pom.xml index d65ae4cf..347882de 100644 --- a/pom.xml +++ b/pom.xml @@ -182,6 +182,13 @@ jackson-databind ${jackson.version} + + + com.google.code.gson + gson + 2.3 + + io.fastjson boon diff --git a/system.properties b/system.properties index 4d46ac0e..3e06d15e 100644 --- a/system.properties +++ b/system.properties @@ -1 +1 @@ -java.runtime.version=1.7 \ No newline at end of file +java.runtime.version=1.6 \ No newline at end of file