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 49775de0..aab2921d 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java @@ -2,9 +2,11 @@ package com.jayway.jsonpath; import com.jayway.jsonpath.internal.Path; import com.jayway.jsonpath.internal.PathCompiler; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.math.BigDecimal; import java.util.Arrays; import java.util.Collection; import java.util.LinkedList; @@ -33,7 +35,7 @@ public class Criteria implements Predicate { EQ { @Override boolean eval(Object expected, Object actual, Configuration configuration) { - boolean res = (0 == configuration.jsonProvider().compare(expected, actual)); + boolean res = (0 == safeCompare(expected, actual)); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); return res; } @@ -41,7 +43,7 @@ public class Criteria implements Predicate { NE { @Override boolean eval(Object expected, Object actual, Configuration configuration) { - boolean res = (0 != configuration.jsonProvider().compare(expected, actual)); + boolean res = (0 != safeCompare(expected, actual)); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); return res; } @@ -52,7 +54,7 @@ public class Criteria implements Predicate { if ((expected == null) ^ (actual == null)) { return false; } - boolean res = (0 > configuration.jsonProvider().compare(expected, actual)); + boolean res = (0 > safeCompare(expected, actual)); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); return res; } @@ -63,7 +65,7 @@ public class Criteria implements Predicate { if ((expected == null) ^ (actual == null)) { return false; } - boolean res = (0 >= configuration.jsonProvider().compare(expected, actual)); + boolean res = (0 >= safeCompare(expected, actual)); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); return res; } @@ -74,7 +76,7 @@ public class Criteria implements Predicate { if ((expected == null) ^ (actual == null)) { return false; } - boolean res = (0 < configuration.jsonProvider().compare(expected, actual)); + boolean res = (0 < safeCompare(expected, actual)); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); return res; } @@ -85,7 +87,7 @@ public class Criteria implements Predicate { if ((expected == null) ^ (actual == null)) { return false; } - boolean res = (0 <= configuration.jsonProvider().compare(expected, actual)); + boolean res = (0 <= safeCompare(expected, actual)); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); return res; } @@ -96,7 +98,7 @@ public class Criteria implements Predicate { boolean res = false; Collection exps = (Collection) expected; for (Object exp : exps) { - if (0 == configuration.jsonProvider().compare(exp, actual)) { + if (0 == safeCompare(exp, actual)) { res = true; break; } @@ -123,7 +125,7 @@ public class Criteria implements Predicate { for (Object exp : exps) { boolean found = false; for (Object check : configuration.jsonProvider().toIterable(actual)) { - if (0 == configuration.jsonProvider().compare(exp, check)) { + if (0 == safeCompare(exp, check)) { found = true; break; } @@ -150,8 +152,8 @@ public class Criteria implements Predicate { int length = configuration.jsonProvider().length(actual); res = (length == size); logger.debug("Array with size {} {} {} => {}", length, name(), size, res); - } else if (configuration.jsonProvider().isString(actual)) { - int length = configuration.jsonProvider().length(actual); + } else if (actual instanceof String) { + int length = ((String) actual).length(); res = length == size; logger.debug("String with length {} {} {} => {}", length, name(), size, res); } else { @@ -567,14 +569,49 @@ public class Criteria implements Predicate { return this; } + private static int safeCompare(Object expected, Object providerParsed) throws ValueCompareException { + + boolean expNullish = isNullish(expected); + boolean provNullish = isNullish(providerParsed); + + if (expNullish && !provNullish) { + return -1; + } else if (!expNullish && provNullish) { + return 1; + } else if (expNullish && provNullish) { + return 0; + } else if (expected instanceof String && providerParsed instanceof String) { + return ((String) expected).compareTo((String) providerParsed); + } else if (expected instanceof Number && providerParsed instanceof Number) { + return new BigDecimal(expected.toString()).compareTo(new BigDecimal(providerParsed.toString())); + } else if (expected instanceof String && providerParsed instanceof Number) { + return new BigDecimal(expected.toString()).compareTo(new BigDecimal(providerParsed.toString())); + } else if (expected instanceof String && providerParsed instanceof Boolean) { + Boolean e = Boolean.valueOf((String) expected); + Boolean a = (Boolean) providerParsed; + return e.compareTo(a); + } else if (expected instanceof Boolean && providerParsed instanceof Boolean) { + Boolean e = (Boolean) expected; + Boolean a = (Boolean) providerParsed; + return e.compareTo(a); + } else { + logger.debug("Can not compare a {} with a {}", expected.getClass().getName(), providerParsed.getClass().getName()); + throw new ValueCompareException(); + } + } + + private static boolean isNullish(Object o) { + return (o == null || ((o instanceof String) && ("null".equals(o)))); + } + public static Criteria create(String path, String operator, String expected) { - if (! expected.isEmpty() && expected.charAt(0) == '\'' && expected.charAt(expected.length()-1) == '\'') { + if (!expected.isEmpty() && expected.charAt(0) == '\'' && expected.charAt(expected.length() - 1) == '\'') { expected = expected.substring(1, expected.length() - 1); } Path p = PathCompiler.compile(path); - if("$".equals(path) && (operator == null || operator.isEmpty()) && (expected == null || expected.isEmpty()) ){ + if ("$".equals(path) && (operator == null || operator.isEmpty()) && (expected == null || expected.isEmpty())) { return new Criteria(p, CriteriaType.NE, null); } else if (operator.isEmpty()) { return Criteria.where(path).exists(true); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/GsonConverter.java b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/GsonConverter.java index 4be46efa..95267642 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/GsonConverter.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/GsonConverter.java @@ -1,17 +1,21 @@ package com.jayway.jsonpath.internal.spi.converter; import com.google.gson.JsonArray; +import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.internal.spi.json.GsonProvider; import com.jayway.jsonpath.spi.converter.ConversionException; import java.math.BigDecimal; import java.math.BigInteger; import java.text.DateFormat; import java.text.ParseException; +import java.util.ArrayList; import java.util.Date; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -31,9 +35,7 @@ public class GsonConverter extends ConverterBase { register(JsonPrimitive.class, Boolean.class); register(JsonArray.class, List.class); - register(JsonArray.class, Map.class); - - + register(JsonObject.class, Map.class); } @Override @@ -67,6 +69,7 @@ public class GsonConverter extends ConverterBase { } else if (targetType.equals(Boolean.class)) { return primitive.getAsBoolean(); } else if (targetType.equals(Date.class)) { + if(primitive.isNumber()){ return new Date(primitive.getAsLong()); } else if(primitive.isString()){ @@ -80,9 +83,43 @@ public class GsonConverter extends ConverterBase { } else if (JsonObject.class.isAssignableFrom(srcType)) { + JsonObject srcObject = (JsonObject) src; + if(targetType.equals(Map.class)){ + Map targetMap = new LinkedHashMap(); + for (Map.Entry entry : srcObject.entrySet()) { + Object val = null; + JsonElement element = entry.getValue(); + if(element.isJsonPrimitive()) { + val = GsonProvider.unwrap(element); + } else if(element.isJsonArray()){ + val = convert(element, element.getClass(), List.class, conf); + } else if(element.isJsonObject()){ + val = convert(element, element.getClass(), Map.class, conf); + } else if(element.isJsonNull()){ + val = null; + } + targetMap.put(entry.getKey(), val); + } + return targetMap; + } } else if (JsonArray.class.isAssignableFrom(srcType)) { - + JsonArray srcArray = (JsonArray) src; + if(targetType.equals(List.class)){ + List targetList = new ArrayList(); + for (JsonElement element : srcArray) { + if(element.isJsonPrimitive()) { + targetList.add(GsonProvider.unwrap(element)); + } else if(element.isJsonArray()){ + targetList.add(convert(element, element.getClass(), List.class, conf)); + } else if(element.isJsonObject()){ + targetList.add(convert(element, element.getClass(), Map.class, conf)); + } else if(element.isJsonNull()){ + targetList.add(null); + } + } + return targetList; + } } return null; 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 3442ff97..42ed62bb 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 @@ -14,12 +14,10 @@ */ package com.jayway.jsonpath.internal.spi.json; -import com.jayway.jsonpath.ValueCompareException; import com.jayway.jsonpath.spi.json.JsonProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.math.BigDecimal; import java.util.Collection; import java.util.List; import java.util.Map; @@ -28,45 +26,6 @@ public abstract class AbstractJsonProvider implements JsonProvider { private static final Logger logger = LoggerFactory.getLogger(AbstractJsonProvider.class); - public Object unwrap(Object obj){ - return obj; - } - - public int compare(Object expected, Object providerParsed) throws ValueCompareException { - - boolean expNullish = isNullish(expected); - boolean provNullish = isNullish(providerParsed); - - if (expNullish && !provNullish) { - return -1; - } else if (!expNullish && provNullish) { - return 1; - } else if (expNullish && provNullish) { - return 0; - } else if (expected instanceof String && providerParsed instanceof String) { - return ((String) expected).compareTo((String) providerParsed); - } else if (expected instanceof Number && providerParsed instanceof Number) { - return new BigDecimal(expected.toString()).compareTo(new BigDecimal(providerParsed.toString())); - } else if (expected instanceof String && providerParsed instanceof Number) { - return new BigDecimal(expected.toString()).compareTo(new BigDecimal(providerParsed.toString())); - } else if (expected instanceof String && providerParsed instanceof Boolean) { - Boolean e = Boolean.valueOf((String)expected); - Boolean a = (Boolean) providerParsed; - return e.compareTo(a); - } else if (expected instanceof Boolean && providerParsed instanceof Boolean) { - Boolean e = (Boolean) expected; - Boolean a = (Boolean) providerParsed; - return e.compareTo(a); - } else { - logger.debug("Can not compare a {} with a {}", expected.getClass().getName(), providerParsed.getClass().getName()); - throw new ValueCompareException(); - } - } - - private static boolean isNullish(Object o){ - return (o == null || ((o instanceof String) && ("null".equals(o)))); - } - @Override public Object createNull(){ return null; @@ -82,11 +41,6 @@ public abstract class AbstractJsonProvider implements JsonProvider { return (obj instanceof List); } - public boolean isString(Object obj){ - return (obj instanceof String); - } - - /** * Extracts a value from an array * 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 index 5829cfc8..20490d2c 100644 --- 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 @@ -2,28 +2,19 @@ package com.jayway.jsonpath.internal.spi.json; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.InstanceCreator; import com.google.gson.JsonArray; -import com.google.gson.JsonDeserializationContext; -import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonNull; import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; import com.google.gson.internal.LazilyParsedNumber; import com.jayway.jsonpath.InvalidJsonException; -import com.jayway.jsonpath.ValueCompareException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.Reader; -import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; @@ -35,58 +26,12 @@ public class GsonProvider extends AbstractJsonProvider { private static final Logger logger = LoggerFactory.getLogger(GsonProvider.class); private static final JsonParser parser = new JsonParser(); - private static final Gson gson = new GsonBuilder().registerTypeAdapter(Number.class, new NumberTypeAdapter()).create(); + private static final Gson gson = new GsonBuilder().create(); - static { - //ConverterFactory.registerConverter(); + public static Object unwrap(Object o) { - } - - public int compare(Object expected, Object providerParsed) throws ValueCompareException { - - JsonElement element = (JsonElement) providerParsed; - - boolean nullish = isNullish(expected); - - if (nullish && !element.isJsonNull()) { - return -1; - } else if (!nullish && element.isJsonNull()) { - return 1; - } else if (nullish && element.isJsonNull()) { - return 0; - } - if(element.isJsonPrimitive()){ - JsonPrimitive primitive = element.getAsJsonPrimitive(); - - if (expected instanceof String && primitive.isString()) { - return ((String) expected).compareTo(primitive.getAsString()); - } else if (expected instanceof Number && primitive.isNumber()) { - return new BigDecimal(expected.toString()).compareTo(new BigDecimal(primitive.toString())); - } else if (expected instanceof String && primitive.isNumber()) { - return new BigDecimal(expected.toString()).compareTo(new BigDecimal(primitive.toString())); - } else if (expected instanceof String && primitive.isBoolean()) { - Boolean e = Boolean.valueOf((String)expected); - Boolean a = primitive.getAsBoolean(); - return e.compareTo(a); - } else if (expected instanceof Boolean && primitive.isBoolean()) { - Boolean e = (Boolean) expected; - Boolean a = primitive.getAsBoolean(); - return e.compareTo(a); - } - } - logger.debug("Can not compare a {} with a {}", expected.getClass().getName(), providerParsed.getClass().getName()); - throw new ValueCompareException(); - } - - private static boolean isNullish(Object o){ - return (o == null || ((o instanceof String) && ("null".equals(o)))); - } - - - public Object unwrap(Object o) { - return o; - /* + System.out.println("unwrap " + o); if (o == null) { return null; } @@ -94,46 +39,25 @@ public class GsonProvider extends AbstractJsonProvider { return o; } - Object unwrapped = null; - JsonElement e = (JsonElement) o; if (e.isJsonNull()) { - unwrapped = null; + return null; } else if (e.isJsonPrimitive()) { JsonPrimitive p = e.getAsJsonPrimitive(); if (p.isString()) { - unwrapped = p.getAsString(); + return p.getAsString(); } else if (p.isBoolean()) { - unwrapped = p.getAsBoolean(); + return p.getAsBoolean(); } else if (p.isNumber()) { - unwrapped = unwrapNumber(p.getAsNumber()); - } - } else { - //unwrapped = o; - if (e.isJsonArray()) { - JsonArray res = new JsonArray(); - for (JsonElement jsonElement : e.getAsJsonArray()) { - if(jsonElement.isJsonPrimitive()){ - JsonPrimitive primitive = jsonElement.getAsJsonPrimitive(); - if(primitive.isNumber()){ - res.add(new JsonPrimitive(unwrapNumber(primitive.getAsNumber()))); - } - } - } - unwrapped = res; - //unwrapped = gson.fromJson(e, List.class); - } else { - unwrapped = gson.fromJson(e, Map.class); + return unwrapNumber(p.getAsNumber()); } - } - return unwrapped; - */ + return o; } - private Number unwrapNumber(Number n){ + private static Number unwrapNumber(Number n) { Number unwrapped; if (n instanceof LazilyParsedNumber) { @@ -146,11 +70,7 @@ public class GsonProvider extends AbstractJsonProvider { unwrapped = bigDecimal.longValue(); } } else { - if (bigDecimal.compareTo(new BigDecimal(Float.MAX_VALUE)) <= 0) { - unwrapped = bigDecimal.floatValue(); - } else { - unwrapped = bigDecimal.doubleValue(); - } + unwrapped = bigDecimal.doubleValue(); } } else { unwrapped = n; @@ -175,7 +95,7 @@ public class GsonProvider extends AbstractJsonProvider { @Override - public Object createNull(){ + public Object createNull() { return JsonNull.INSTANCE; } @@ -186,33 +106,24 @@ public class GsonProvider extends AbstractJsonProvider { @Override public boolean isArray(Object obj) { - return (obj instanceof JsonArray); - } - - public boolean isString(Object obj){ - if(obj == null) { - return false; - } - JsonElement element = toJsonElement(obj); - if(element.isJsonPrimitive()){ - return element.getAsJsonPrimitive().isString(); - } - return false; + return (obj instanceof JsonArray || obj instanceof List); } @Override public Object getArrayIndex(Object obj, int idx) { - return toJsonArray(obj).get(idx); + System.out.println("getArrayIndex " + obj + " (" + obj.getClass() + ")"); + return unwrap(toJsonArray(obj).get(idx)); } @Override public Object getMapValue(Object obj, String key) { - Object o = toJsonObject(obj).get(key); - if (o == null) { + JsonObject jsonObject = toJsonObject(obj); + Object o = jsonObject.get(key); + if (!jsonObject.has(key)) { return UNDEFINED; } else { - return o; + return unwrap(o); } } @@ -238,11 +149,14 @@ public class GsonProvider extends AbstractJsonProvider { @Override public boolean isMap(Object obj) { - return (obj instanceof JsonObject) ; + System.out.println("isMap " + obj + " (" + obj.getClass() + ")"); + //return (obj instanceof JsonObject || obj instanceof Map); + return (obj instanceof JsonObject); } @Override public Collection getPropertyKeys(Object obj) { + System.out.println("getPropertyKeys " + obj); List keys = new ArrayList(); for (Map.Entry entry : toJsonObject(obj).entrySet()) { keys.add(entry.getKey()); @@ -252,30 +166,37 @@ public class GsonProvider extends AbstractJsonProvider { @Override public int length(Object obj) { + System.out.println("length " + obj); if (isArray(obj)) { return toJsonArray(obj).size(); - } else if(isMap(obj)){ + } else if (isMap(obj)) { return toJsonObject(obj).entrySet().size(); } else { - if(obj instanceof JsonElement){ + if (obj instanceof JsonElement) { JsonElement element = toJsonElement(obj); - if(element.isJsonPrimitive()){ + if (element.isJsonPrimitive()) { return element.toString().length(); } } } - throw new RuntimeException("length operation can not applied to " + obj!=null?obj.getClass().getName():"null"); + throw new RuntimeException("length operation can not applied to " + obj != null ? obj.getClass().getName() : "null"); } @Override public Iterable toIterable(Object obj) { + System.out.println("toIterable " + obj + " (" + obj.getClass() + ")"); if (isArray(obj)) { - return toJsonArray(obj); + JsonArray arr = toJsonArray(obj); + List values = new ArrayList(arr.size()); + for (Object o : arr) { + values.add(unwrap(o)); + } + return values; } else { - List values = new ArrayList(); JsonObject jsonObject = toJsonObject(obj); + List values = new ArrayList(); for (Map.Entry entry : jsonObject.entrySet()) { - values.add(entry.getValue()); + values.add(unwrap(entry.getValue())); } return values; } @@ -296,53 +217,4 @@ public class GsonProvider extends AbstractJsonProvider { private JsonElement toJsonElement(Object o) { return (JsonElement) o; } - - - public static class NumberTypeAdapter - implements JsonSerializer, JsonDeserializer, - InstanceCreator { - - public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext - context) { - return new JsonPrimitive(src); - } - - public Number deserialize(JsonElement json, Type typeOfT, - JsonDeserializationContext context) - throws JsonParseException { - - Number res = null; - JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive(); - if (jsonPrimitive.isNumber()) { - Number n = jsonPrimitive.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) { - res = bigDecimal.intValue(); - } else { - res = bigDecimal.longValue(); - } - } else { - if (bigDecimal.compareTo(new BigDecimal(Float.MAX_VALUE)) <= 0) { - res = bigDecimal.floatValue(); - } else { - res = bigDecimal.doubleValue(); - } - } - } - } else { - throw new IllegalStateException("Expected a number field, but was " + json); - } - return res; - } - - - - public Number createInstance(Type type) { - return 1L; - } - } - } 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 cb630ae8..45ed5dd4 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,10 +24,6 @@ public interface JsonProvider { static final Object UNDEFINED = new Object(); - Object unwrap(Object obj); - - int compare(Object expected, Object providerParsed) throws ValueCompareException; - Object parse(String json) throws InvalidJsonException; Object parse(InputStream jsonStream) throws InvalidJsonException; @@ -46,15 +42,6 @@ public interface JsonProvider { */ boolean isArray(Object obj); - /** - * checks if object is a string - * - * @param obj object to check - * @return true if obj is an array - */ - boolean isString(Object obj); - - /** * Get the length of an json array, json object or a json string * diff --git a/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java b/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java index 4a925035..079e1f67 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java @@ -27,8 +27,7 @@ public class BaseTest { return new DefaultConversionProvider(); } }); - } - */ + }*/