Browse Source

Merge branch 'master' of github.com:jayway/JsonPath into remove-unused-jsonprovider-methods

Conflicts:
	json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java
pull/52/head
Jochen Berger 10 years ago
parent
commit
5aa37eb7b1
  1. 2
      json-path-web-test/src/main/java/com/jayway/jsonpath/web/bench/Bench.java
  2. 6
      json-path/pom.xml
  3. 65
      json-path/src/main/java/com/jayway/jsonpath/Configuration.java
  4. 84
      json-path/src/main/java/com/jayway/jsonpath/Criteria.java
  5. 22
      json-path/src/main/java/com/jayway/jsonpath/JsonPath.java
  6. 7
      json-path/src/main/java/com/jayway/jsonpath/ReadContext.java
  7. 4
      json-path/src/main/java/com/jayway/jsonpath/ValueCompareException.java
  8. 18
      json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java
  9. 79
      json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java
  10. 14
      json-path/src/main/java/com/jayway/jsonpath/internal/compiler/EvaluationContextImpl.java
  11. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/compiler/PathToken.java
  12. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/compiler/PredicatePathToken.java
  13. 9
      json-path/src/main/java/com/jayway/jsonpath/internal/compiler/ScanPathToken.java
  14. 40
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/ConverterBase.java
  15. 38
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/DateConverter.java
  16. 66
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/DefaultConversionProvider.java
  17. 90
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/GsonConverter.java
  18. 130
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/NumberConverter.java
  19. 25
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/StringConverter.java
  20. 75
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java
  21. 348
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonProvider.java
  22. 21
      json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConversionException.java
  23. 10
      json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConversionProvider.java
  24. 69
      json-path/src/main/java/com/jayway/jsonpath/spi/converter/Converter.java
  25. 174
      json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConverterFactory.java
  26. 28
      json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java
  27. 31
      json-path/src/test/java/com/jayway/jsonpath/BaseTest.java
  28. 19
      json-path/src/test/java/com/jayway/jsonpath/ConverterTest.java
  29. 4
      json-path/src/test/java/com/jayway/jsonpath/FilterTest.java
  30. 12
      json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java
  31. 10
      json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java
  32. 2
      json-path/src/test/java/com/jayway/jsonpath/old/FilterTest.java
  33. 5
      json-path/src/test/java/com/jayway/jsonpath/old/JsonPathTest.java
  34. 3
      json-path/src/test/java/com/jayway/jsonpath/old/internal/ScanPathTokenTest.java
  35. 7
      pom.xml
  36. 2
      system.properties

2
json-path-web-test/src/main/java/com/jayway/jsonpath/web/bench/Bench.java

@ -70,7 +70,7 @@ public class Bench {
} else if (res instanceof Boolean) { } else if (res instanceof Boolean) {
result = res.toString(); result = res.toString();
} else { } else {
result = res != null ? Configuration.defaultConfiguration().getProvider().toJson(res) : "null"; result = res != null ? Configuration.defaultConfiguration().jsonProvider().toJson(res) : "null";
} }
return new Result("jayway", time, result, error); return new Result("jayway", time, result, error);
} }

6
json-path/pom.xml

@ -35,6 +35,12 @@
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
<build> <build>

65
json-path/src/main/java/com/jayway/jsonpath/Configuration.java

@ -14,7 +14,9 @@
*/ */
package com.jayway.jsonpath; package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.spi.converter.DefaultConversionProvider;
import com.jayway.jsonpath.internal.spi.json.JsonSmartJsonProvider; import com.jayway.jsonpath.internal.spi.json.JsonSmartJsonProvider;
import com.jayway.jsonpath.spi.converter.ConversionProvider;
import com.jayway.jsonpath.spi.json.JsonProvider; import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.Collections; import java.util.Collections;
@ -28,7 +30,7 @@ public class Configuration {
private static Defaults DEFAULTS = new Defaults() { private static Defaults DEFAULTS = new Defaults() {
@Override @Override
public JsonProvider provider() { public JsonProvider jsonProvider() {
return new JsonSmartJsonProvider(); return new JsonSmartJsonProvider();
} }
@ -36,38 +38,54 @@ public class Configuration {
public Set<Option> options() { public Set<Option> options() {
return EnumSet.noneOf(Option.class); return EnumSet.noneOf(Option.class);
} }
@Override
public ConversionProvider conversionProvider() {
return new DefaultConversionProvider();
}
}; };
public static synchronized void setDefaults(Defaults defaults){ public static synchronized void setDefaults(Defaults defaults){
DEFAULTS = defaults; DEFAULTS = defaults;
} }
private final JsonProvider provider; private final JsonProvider jsonProvider;
private final ConversionProvider conversionProvider;
private final Set<Option> options; private final Set<Option> options;
private Configuration(JsonProvider provider, EnumSet<Option> options) { private Configuration(JsonProvider jsonProvider, ConversionProvider conversionProvider, EnumSet<Option> options) {
notNull(provider, "provider can not be null"); notNull(jsonProvider, "jsonProvider can not be null");
notNull(conversionProvider, "conversionProvider can not be null");
notNull(options, "options can not be null"); notNull(options, "options can not be null");
this.provider = provider; this.jsonProvider = jsonProvider;
this.conversionProvider = conversionProvider;
this.options = Collections.unmodifiableSet(options); this.options = Collections.unmodifiableSet(options);
} }
public Configuration provider(JsonProvider provider) { public Configuration jsonProvider(JsonProvider newJsonProvider) {
return Configuration.builder().jsonProvider(provider).options(options).build(); return Configuration.builder().jsonProvider(newJsonProvider).conversionProvider(conversionProvider).options(options).build();
}
public JsonProvider jsonProvider() {
return jsonProvider;
}
public ConversionProvider conversionProvider() {
return conversionProvider;
} }
public JsonProvider getProvider() { public Configuration conversionProvider(ConversionProvider newConversionProvider) {
return provider; return Configuration.builder().jsonProvider(jsonProvider).conversionProvider(newConversionProvider).options(options).build();
} }
public Configuration addOptions(Option... options) { public Configuration addOptions(Option... options) {
EnumSet<Option> opts = EnumSet.noneOf(Option.class); EnumSet<Option> opts = EnumSet.noneOf(Option.class);
opts.addAll(this.options); opts.addAll(this.options);
opts.addAll(asList(options)); opts.addAll(asList(options));
return Configuration.builder().jsonProvider(provider).options(opts).build(); return Configuration.builder().jsonProvider(jsonProvider).conversionProvider(conversionProvider).options(opts).build();
} }
public Configuration options(Option... options) { public Configuration options(Option... options) {
return Configuration.builder().jsonProvider(provider).options(options).build(); return Configuration.builder().jsonProvider(jsonProvider).conversionProvider(conversionProvider).options(options).build();
} }
public Set<Option> getOptions() { public Set<Option> getOptions() {
@ -80,7 +98,7 @@ public class Configuration {
public static Configuration defaultConfiguration() { public static Configuration defaultConfiguration() {
return Configuration.builder().jsonProvider(DEFAULTS.provider()).options(DEFAULTS.options()).build(); return Configuration.builder().jsonProvider(DEFAULTS.jsonProvider()).options(DEFAULTS.options()).build();
} }
public static ConfigurationBuilder builder() { public static ConfigurationBuilder builder() {
@ -89,11 +107,17 @@ public class Configuration {
public static class ConfigurationBuilder { public static class ConfigurationBuilder {
private JsonProvider provider; private JsonProvider jsonProvider;
private ConversionProvider conversionProvider;
private EnumSet<Option> options = EnumSet.noneOf(Option.class); private EnumSet<Option> options = EnumSet.noneOf(Option.class);
public ConfigurationBuilder jsonProvider(JsonProvider provider) { public ConfigurationBuilder jsonProvider(JsonProvider provider) {
this.provider = provider; this.jsonProvider = provider;
return this;
}
public ConfigurationBuilder conversionProvider(ConversionProvider provider) {
this.conversionProvider = provider;
return this; return this;
} }
@ -110,18 +134,23 @@ public class Configuration {
} }
public Configuration build() { public Configuration build() {
if (provider == null) { if (jsonProvider == null) {
provider = DEFAULTS.provider(); jsonProvider = DEFAULTS.jsonProvider();
}
if(conversionProvider == null){
conversionProvider = DEFAULTS.conversionProvider();
} }
return new Configuration(provider, options); return new Configuration(jsonProvider, conversionProvider, options);
} }
} }
public interface Defaults { public interface Defaults {
JsonProvider provider(); JsonProvider jsonProvider();
Set<Option> options(); Set<Option> options();
ConversionProvider conversionProvider();
} }
} }

84
json-path/src/main/java/com/jayway/jsonpath/Criteria.java

@ -5,7 +5,6 @@ import com.jayway.jsonpath.internal.PathCompiler;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
@ -34,7 +33,7 @@ public class Criteria implements Predicate {
EQ { EQ {
@Override @Override
boolean eval(Object expected, Object actual, Configuration configuration) { boolean eval(Object expected, Object actual, Configuration configuration) {
boolean res = (0 == safeCompare(expected, actual, configuration)); boolean res = (0 == configuration.jsonProvider().compare(expected, actual));
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res);
return res; return res;
} }
@ -42,7 +41,7 @@ public class Criteria implements Predicate {
NE { NE {
@Override @Override
boolean eval(Object expected, Object actual, Configuration configuration) { boolean eval(Object expected, Object actual, Configuration configuration) {
boolean res = (0 != safeCompare(expected, actual, configuration)); boolean res = (0 != configuration.jsonProvider().compare(expected, actual));
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res);
return res; return res;
} }
@ -53,7 +52,7 @@ public class Criteria implements Predicate {
if ((expected == null) ^ (actual == null)) { if ((expected == null) ^ (actual == null)) {
return false; return false;
} }
boolean res = (0 > safeCompare(expected, actual, configuration)); boolean res = (0 > configuration.jsonProvider().compare(expected, actual));
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res);
return res; return res;
} }
@ -64,7 +63,7 @@ public class Criteria implements Predicate {
if ((expected == null) ^ (actual == null)) { if ((expected == null) ^ (actual == null)) {
return false; return false;
} }
boolean res = (0 >= safeCompare(expected, actual, configuration)); boolean res = (0 >= configuration.jsonProvider().compare(expected, actual));
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res);
return res; return res;
} }
@ -75,7 +74,7 @@ public class Criteria implements Predicate {
if ((expected == null) ^ (actual == null)) { if ((expected == null) ^ (actual == null)) {
return false; return false;
} }
boolean res = (0 < safeCompare(expected, actual, configuration)); boolean res = (0 < configuration.jsonProvider().compare(expected, actual));
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res);
return res; return res;
} }
@ -86,7 +85,7 @@ public class Criteria implements Predicate {
if ((expected == null) ^ (actual == null)) { if ((expected == null) ^ (actual == null)) {
return false; return false;
} }
boolean res = (0 <= safeCompare(expected, actual, configuration)); boolean res = (0 <= configuration.jsonProvider().compare(expected, actual));
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res);
return res; return res;
} }
@ -97,7 +96,7 @@ public class Criteria implements Predicate {
boolean res = false; boolean res = false;
Collection exps = (Collection) expected; Collection exps = (Collection) expected;
for (Object exp : exps) { for (Object exp : exps) {
if (0 == safeCompare(exp, actual, configuration)) { if (0 == configuration.jsonProvider().compare(exp, actual)) {
res = true; res = true;
break; break;
} }
@ -120,11 +119,11 @@ public class Criteria implements Predicate {
boolean eval(Object expected, Object actual, Configuration configuration) { boolean eval(Object expected, Object actual, Configuration configuration) {
boolean res = true; boolean res = true;
Collection exps = (Collection) expected; Collection exps = (Collection) expected;
if (configuration.getProvider().isArray(actual)) { if (configuration.jsonProvider().isArray(actual)) {
for (Object exp : exps) { for (Object exp : exps) {
boolean found = false; boolean found = false;
for (Object check : configuration.getProvider().toIterable(actual)) { for (Object check : configuration.jsonProvider().toIterable(actual)) {
if (0 == safeCompare(exp, check, configuration)) { if (0 == configuration.jsonProvider().compare(exp, check)) {
found = true; found = true;
break; break;
} }
@ -134,7 +133,7 @@ public class Criteria implements Predicate {
break; break;
} }
} }
logger.debug("[{}] {} [{}] => {}", join(", ", configuration.getProvider().toIterable(actual)), name(), join(", ", exps), res); logger.debug("[{}] {} [{}] => {}", join(", ", configuration.jsonProvider().toIterable(actual)), name(), join(", ", exps), res);
} else { } else {
res = false; res = false;
logger.debug("[{}] {} [{}] => {}", "<NOT AN ARRAY>", name(), join(", ", exps), res); logger.debug("[{}] {} [{}] => {}", "<NOT AN ARRAY>", name(), join(", ", exps), res);
@ -147,12 +146,12 @@ public class Criteria implements Predicate {
boolean eval(Object expected, Object actual, Configuration configuration) { boolean eval(Object expected, Object actual, Configuration configuration) {
int size = (Integer) expected; int size = (Integer) expected;
boolean res; boolean res;
if (configuration.getProvider().isArray(actual)) { if (configuration.jsonProvider().isArray(actual)) {
int length = configuration.getProvider().length(actual); int length = configuration.jsonProvider().length(actual);
res = length == size; res = (length == size);
logger.debug("Array with size {} {} {} => {}", length, name(), size, res); logger.debug("Array with size {} {} {} => {}", length, name(), size, res);
} else if (actual instanceof String) { } else if (configuration.jsonProvider().isString(actual)) {
int length = ((String) actual).length(); int length = configuration.jsonProvider().length(actual);
res = length == size; res = length == size;
logger.debug("String with length {} {} {} => {}", length, name(), size, res); logger.debug("String with length {} {} {} => {}", length, name(), size, res);
} else { } else {
@ -212,8 +211,8 @@ public class Criteria implements Predicate {
boolean eval(Object expected, Object actual, Configuration configuration) { boolean eval(Object expected, Object actual, Configuration configuration) {
boolean res = false; boolean res = false;
if (actual != null) { if (actual != null) {
if (configuration.getProvider().isArray(actual)) { if (configuration.jsonProvider().isArray(actual)) {
int len = configuration.getProvider().length(actual); int len = configuration.jsonProvider().length(actual);
res = (0 != len); res = (0 != len);
logger.debug("array length = {} {} => {}", len, name(), res); logger.debug("array length = {} {} => {}", len, name(), res);
} else if (actual instanceof String) { } else if (actual instanceof String) {
@ -281,21 +280,18 @@ public class Criteria implements Predicate {
if (CriteriaType.EXISTS == criteriaType) { if (CriteriaType.EXISTS == criteriaType) {
boolean exists = ((Boolean) expected); boolean exists = ((Boolean) expected);
try { try {
Configuration c = ctx.configuration(); Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options().build();
if(c.containsOption(Option.ALWAYS_RETURN_LIST) || c.containsOption(Option.SUPPRESS_EXCEPTIONS)){
c = c.options();
}
path.evaluate(ctx.target(), c).getValue(); path.evaluate(ctx.target(), c).getValue();
return exists; return exists;
} catch (PathNotFoundException e) { } catch (PathNotFoundException e) {
return !exists; return !exists;
} }
} else { } else {
try { try {
final Object actual = path.evaluate(ctx.target(), ctx.configuration()).getValue(); final Object actual = path.evaluate(ctx.target(), ctx.configuration()).getValue();
return criteriaType.eval(expected, actual, ctx.configuration()); return criteriaType.eval(expected, actual, ctx.configuration());
} catch (CompareException e) { } catch (ValueCompareException e) {
return false; return false;
} catch (PathNotFoundException e) { } catch (PathNotFoundException e) {
return false; return false;
@ -571,44 +567,8 @@ public class Criteria implements Predicate {
return this; return this;
} }
private static int safeCompare(Object expected, Object actual, Configuration configuration) {
if (isNullish(expected) && !isNullish(actual)) {
return -1;
} else if (!isNullish(expected) && isNullish(actual)) {
return 1;
} else if (isNullish(expected) && isNullish(actual)) {
return 0;
} else if (expected instanceof String && actual instanceof String) {
return ((String) expected).compareTo((String) actual);
} else if (expected instanceof Number && actual instanceof Number) {
return new BigDecimal(expected.toString()).compareTo(new BigDecimal(actual.toString()));
} else if (expected instanceof String && actual instanceof Number) {
return new BigDecimal(expected.toString()).compareTo(new BigDecimal(actual.toString()));
} else if (expected instanceof String && actual instanceof Boolean) {
Boolean e = Boolean.valueOf((String)expected);
Boolean a = (Boolean) actual;
return e.compareTo(a);
} else if (expected instanceof Boolean && actual instanceof Boolean) {
Boolean e = (Boolean) expected;
Boolean a = (Boolean) actual;
return e.compareTo(a);
} else {
logger.debug("Can not compare a {} with a {}", expected.getClass().getName(), actual.getClass().getName());
throw new CompareException();
}
}
private static boolean isNullish(Object o){
return (o == null || ((o instanceof String) && ("null".equals(o))));
}
private static class CompareException extends RuntimeException {
}
public static Criteria create(String path, String operator, String expected) { public static Criteria create(String path, String operator, String expected) {
if (expected.startsWith("'") && expected.endsWith("'")) { if (! expected.isEmpty() && expected.charAt(0) == '\'' && expected.charAt(expected.length()-1) == '\'') {
expected = expected.substring(1, expected.length() - 1); expected = expected.substring(1, expected.length() - 1);
} }

22
json-path/src/main/java/com/jayway/jsonpath/JsonPath.java

@ -176,8 +176,8 @@ public class JsonPath {
} else { } else {
Object res = path.evaluate(jsonObject, configuration).getValue(); Object res = path.evaluate(jsonObject, configuration).getValue();
if(optAlwaysReturnList && path.isDefinite()){ if(optAlwaysReturnList && path.isDefinite()){
Object array = configuration.getProvider().createArray(); Object array = configuration.jsonProvider().createArray();
configuration.getProvider().setProperty(array, 0, res); configuration.jsonProvider().setProperty(array, 0, res);
return (T)array; return (T)array;
} else { } else {
return (T)res; return (T)res;
@ -189,12 +189,12 @@ public class JsonPath {
} }
} }
if(optAsPathList){ if(optAsPathList){
return (T)configuration.getProvider().createArray(); return (T)configuration.jsonProvider().createArray();
} else { } else {
if(optAlwaysReturnList){ if(optAlwaysReturnList){
return (T)configuration.getProvider().createArray(); return (T)configuration.jsonProvider().createArray();
} else { } else {
return (T)(path.isDefinite() ? null : configuration.getProvider().createArray()); return (T)(path.isDefinite() ? null : configuration.jsonProvider().createArray());
} }
} }
@ -226,7 +226,7 @@ public class JsonPath {
notEmpty(json, "json can not be null or empty"); notEmpty(json, "json can not be null or empty");
notNull(configuration, "jsonProvider can not be null"); notNull(configuration, "jsonProvider can not be null");
return read(configuration.getProvider().parse(json), configuration); return read(configuration.jsonProvider().parse(json), configuration);
} }
/** /**
@ -259,7 +259,7 @@ public class JsonPath {
InputStream in = null; InputStream in = null;
try { try {
in = HttpProviderFactory.getProvider().get(jsonURL); in = HttpProviderFactory.getProvider().get(jsonURL);
return read(configuration.getProvider().parse(in), configuration); return read(configuration.jsonProvider().parse(in), configuration);
} finally { } finally {
Utils.closeQuietly(in); Utils.closeQuietly(in);
} }
@ -297,7 +297,7 @@ public class JsonPath {
FileInputStream fis = null; FileInputStream fis = null;
try { try {
fis = new FileInputStream(jsonFile); fis = new FileInputStream(jsonFile);
return read(configuration.getProvider().parse(fis), configuration); return read(configuration.jsonProvider().parse(fis), configuration);
} finally { } finally {
Utils.closeQuietly(fis); Utils.closeQuietly(fis);
} }
@ -331,7 +331,7 @@ public class JsonPath {
notNull(configuration, "configuration can not be null"); notNull(configuration, "configuration can not be null");
try { try {
return read(configuration.getProvider().parse(jsonInputStream), configuration); return read(configuration.jsonProvider().parse(jsonInputStream), configuration);
} finally { } finally {
Utils.closeQuietly(jsonInputStream); Utils.closeQuietly(jsonInputStream);
} }
@ -455,8 +455,8 @@ public class JsonPath {
/** /**
* Creates a {@link ParseContext} that will parse a given JSON input. * Creates a {@link ParseContext} that will parse a given JSON input.
* *
* @param provider provider to use when parsing JSON * @param provider jsonProvider to use when parsing JSON
* @return a parsing context based on given provider * @return a parsing context based on given jsonProvider
*/ */
public static ParseContext using(JsonProvider provider) { public static ParseContext using(JsonProvider provider) {
return new JsonReader(Configuration.builder().jsonProvider(provider).build()); return new JsonReader(Configuration.builder().jsonProvider(provider).build());

7
json-path/src/main/java/com/jayway/jsonpath/ReadContext.java

@ -16,6 +16,13 @@ package com.jayway.jsonpath;
public interface ReadContext { public interface ReadContext {
/**
* Returns the configuration used for reading
*
* @return an immutable configuration
*/
Configuration configuration();
/** /**
* Returns the JSON model that this context is reading * Returns the JSON model that this context is reading
* *

4
json-path/src/main/java/com/jayway/jsonpath/ValueCompareException.java

@ -0,0 +1,4 @@
package com.jayway.jsonpath;
public class ValueCompareException extends RuntimeException {
}

18
json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java

@ -5,7 +5,6 @@ import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.ParseContext; import com.jayway.jsonpath.ParseContext;
import com.jayway.jsonpath.Predicate; import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.ReadContext; import com.jayway.jsonpath.ReadContext;
import com.jayway.jsonpath.spi.converter.ConverterFactory;
import com.jayway.jsonpath.spi.http.HttpProviderFactory; import com.jayway.jsonpath.spi.http.HttpProviderFactory;
import java.io.File; import java.io.File;
@ -46,14 +45,14 @@ public class JsonReader implements ParseContext, ReadContext {
@Override @Override
public ReadContext parse(String json) { public ReadContext parse(String json) {
notEmpty(json, "json string can not be null or empty"); notEmpty(json, "json string can not be null or empty");
this.json = configuration.getProvider().parse(json); this.json = configuration.jsonProvider().parse(json);
return this; return this;
} }
@Override @Override
public ReadContext parse(InputStream json) { public ReadContext parse(InputStream json) {
notNull(json, "json input stream can not be null"); notNull(json, "json input stream can not be null");
this.json = configuration.getProvider().parse(json); this.json = configuration.jsonProvider().parse(json);
return this; return this;
} }
@ -77,6 +76,11 @@ public class JsonReader implements ParseContext, ReadContext {
return parse(is); return parse(is);
} }
@Override
public Configuration configuration() {
return configuration;
}
//------------------------------------------------ //------------------------------------------------
// //
// ReadContext impl // ReadContext impl
@ -95,7 +99,7 @@ public class JsonReader implements ParseContext, ReadContext {
@Override @Override
public <T> T read(String path, Class<T> type, Predicate... filters) { public <T> T read(String path, Class<T> type, Predicate... filters) {
return convert(read(path, filters), type); return convert(read(path, filters), type, configuration);
} }
@Override @Override
@ -106,11 +110,11 @@ public class JsonReader implements ParseContext, ReadContext {
@Override @Override
public <T> T read(JsonPath path, Class<T> type) { public <T> T read(JsonPath path, Class<T> type) {
return convert(read(path), type); return convert(read(path), type, configuration);
} }
private <T> T convert(Object obj, Class<T> type){ private <T> T convert(Object obj, Class<T> targetType, Configuration configuration){
return ConverterFactory.createConverter(type).convert(obj, configuration); return configuration.conversionProvider().convert(obj, targetType, configuration);
} }
} }

79
json-path/src/main/java/com/jayway/jsonpath/internal/PathCompiler.java

@ -5,8 +5,8 @@ import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.InvalidPathException; import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.Predicate; import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.compiler.ArrayPathToken; import com.jayway.jsonpath.internal.compiler.ArrayPathToken;
import com.jayway.jsonpath.internal.compiler.PredicatePathToken;
import com.jayway.jsonpath.internal.compiler.PathToken; import com.jayway.jsonpath.internal.compiler.PathToken;
import com.jayway.jsonpath.internal.compiler.PredicatePathToken;
import com.jayway.jsonpath.internal.compiler.PropertyPathToken; import com.jayway.jsonpath.internal.compiler.PropertyPathToken;
import com.jayway.jsonpath.internal.compiler.RootPathToken; import com.jayway.jsonpath.internal.compiler.RootPathToken;
import com.jayway.jsonpath.internal.compiler.ScanPathToken; import com.jayway.jsonpath.internal.compiler.ScanPathToken;
@ -44,7 +44,7 @@ public class PathCompiler {
LinkedList<Predicate> filterList = new LinkedList<Predicate>(asList(filters)); LinkedList<Predicate> filterList = new LinkedList<Predicate>(asList(filters));
if (!path.startsWith("$")) { if (path.charAt(0) != '$') {
path = "$." + path; path = "$." + path;
} }
@ -57,13 +57,12 @@ public class PathCompiler {
RootPathToken root = null; RootPathToken root = null;
char[] chars = path.toCharArray();
int i = 0; int i = 0;
int positions; int positions;
String fragment = ""; String fragment = "";
do { do {
char current = chars[i]; char current = path.charAt(i);
switch (current) { switch (current) {
case SPACE: case SPACE:
@ -73,27 +72,27 @@ public class PathCompiler {
i++; i++;
break; break;
case BRACKET_OPEN: case BRACKET_OPEN:
positions = fastForwardUntilClosed(chars, i); positions = fastForwardUntilClosed(path, i);
fragment = new String(chars, i, positions); fragment = path.substring(i, i+positions);
i += positions; i += positions;
break; break;
case PERIOD: case PERIOD:
i++; i++;
if (chars[i] == PERIOD) { if (path.charAt(i) == PERIOD) {
//This is a deep scan //This is a deep scan
fragment = ".."; fragment = "..";
i++; i++;
} else { } else {
positions = fastForward(chars, i); positions = fastForward(path, i);
if (positions == 0) { if (positions == 0) {
continue; continue;
} else if (positions == 1 && chars[i] == '*') { } else if (positions == 1 && path.charAt(i) == '*') {
fragment = new String("[*]"); fragment = new String("[*]");
} else { } else {
assertValidFieldChars(chars, i, positions); assertValidFieldChars(path, i, positions);
fragment = PROPERTY_OPEN + new String(chars, i, positions) + PROPERTY_CLOSE; fragment = PROPERTY_OPEN + path.substring(i, i+positions) + PROPERTY_CLOSE;
} }
i += positions; i += positions;
} }
@ -103,9 +102,9 @@ public class PathCompiler {
i++; i++;
break; break;
default: default:
positions = fastForward(chars, i); positions = fastForward(path, i);
fragment = PROPERTY_OPEN + new String(chars, i, positions) + PROPERTY_CLOSE; fragment = PROPERTY_OPEN + path.substring(i, i+positions) + PROPERTY_CLOSE;
i += positions; i += positions;
break; break;
} }
@ -115,7 +114,7 @@ public class PathCompiler {
root.append(PathComponentAnalyzer.analyze(fragment, filterList)); root.append(PathComponentAnalyzer.analyze(fragment, filterList));
} }
} while (i < chars.length); } while (i < path.length());
Path pa = new CompiledPath(root); Path pa = new CompiledPath(root);
@ -124,10 +123,10 @@ public class PathCompiler {
return pa; return pa;
} }
private static void assertValidFieldChars(char[] chars, int start, int positions) { private static void assertValidFieldChars(String s, int start, int positions) {
int i = start; int i = start;
while (i < start + positions) { while (i < start + positions) {
char c = chars[i]; char c = s.charAt(i);
if (!Character.isLetterOrDigit(c) && c != '-' && c != '_' && c != '$' && c != '@') { if (!Character.isLetterOrDigit(c) && c != '-' && c != '_' && c != '$' && c != '@') {
throw new InvalidPathException("Invalid field name! Use bracket notation if your filed names does not match pattern: ([a-zA-Z@][a-zA-Z0-9@\\$_\\-]*)$"); throw new InvalidPathException("Invalid field name! Use bracket notation if your filed names does not match pattern: ([a-zA-Z@][a-zA-Z0-9@\\$_\\-]*)$");
@ -136,10 +135,10 @@ public class PathCompiler {
} }
} }
private static int fastForward(char[] chars, int index) { private static int fastForward(String s, int index) {
int skipCount = 0; int skipCount = 0;
while (index < chars.length) { while (index < s.length()) {
char current = chars[index]; char current = s.charAt(index);
if (current == PERIOD || current == BRACKET_OPEN || current == SPACE) { if (current == PERIOD || current == BRACKET_OPEN || current == SPACE) {
break; break;
} }
@ -149,7 +148,7 @@ public class PathCompiler {
return skipCount; return skipCount;
} }
private static int fastForwardUntilClosed(char[] chars, int index) { private static int fastForwardUntilClosed(String s, int index) {
int skipCount = 0; int skipCount = 0;
int nestedBrackets = 0; int nestedBrackets = 0;
@ -157,8 +156,8 @@ public class PathCompiler {
index++; index++;
skipCount++; skipCount++;
while (index < chars.length) { while (index < s.length()) {
char current = chars[index]; char current = s.charAt(index);
index++; index++;
skipCount++; skipCount++;
@ -185,7 +184,6 @@ public class PathCompiler {
static class PathComponentAnalyzer { static class PathComponentAnalyzer {
private static final Pattern FILTER_PATTERN = Pattern.compile("^\\[\\s*\\?\\s*[,\\s*\\?]*?\\s*]$"); //[?] or [?, ?, ...] private static final Pattern FILTER_PATTERN = Pattern.compile("^\\[\\s*\\?\\s*[,\\s*\\?]*?\\s*]$"); //[?] or [?, ?, ...]
private char[] chars;
private int i; private int i;
private char current; private char current;
@ -218,10 +216,9 @@ public class PathCompiler {
return new PredicatePathToken(filters); return new PredicatePathToken(filters);
} }
this.chars = pathFragment.toCharArray();
this.i = 0; this.i = 0;
do { do {
current = chars[i]; current = pathFragment.charAt(i);
switch (current) { switch (current) {
case '?': case '?':
@ -237,7 +234,7 @@ public class PathCompiler {
} }
} while (i < chars.length); } while (i < pathFragment.length());
throw new InvalidPathException("Could not analyze path component: " + pathFragment); throw new InvalidPathException("Could not analyze path component: " + pathFragment);
} }
@ -259,7 +256,7 @@ public class PathCompiler {
boolean functionBracketClosed = false; boolean functionBracketClosed = false;
boolean propertyOpen = false; boolean propertyOpen = false;
current = chars[++i]; //skip the '?' current = pathFragment.charAt(++i); //skip the '?'
while (current != ']' || bracketCount != 0) { while (current != ']' || bracketCount != 0) {
@ -303,7 +300,7 @@ public class PathCompiler {
} else if (bracketCount == 0 && isLogicOperatorChar(current)) { } else if (bracketCount == 0 && isLogicOperatorChar(current)) {
if (isLogicOperatorChar(chars[i + 1])) { if (isLogicOperatorChar(pathFragment.charAt(i + 1))) {
++i; ++i;
} }
criteria.add(createCriteria(pathBuffer, operatorBuffer, valueBuffer)); criteria.add(createCriteria(pathBuffer, operatorBuffer, valueBuffer));
@ -320,7 +317,7 @@ public class PathCompiler {
break; break;
} }
current = chars[++i]; current = pathFragment.charAt(++i);
} }
if (!functionBracketOpened || !functionBracketClosed) { if (!functionBracketOpened || !functionBracketClosed) {
@ -381,7 +378,7 @@ public class PathCompiler {
} }
break; break;
} }
current = chars[++i]; current = pathFragment.charAt(++i);
} }
return new PropertyPathToken(properties); return new PropertyPathToken(properties);
} }
@ -406,15 +403,15 @@ public class PathCompiler {
if (contextSize) { if (contextSize) {
current = chars[++i]; current = pathFragment.charAt(++i);
current = chars[++i]; current = pathFragment.charAt(++i);
while (current != '-') { while (current != '-') {
if (current == ' ' || current == '(' || current == ')') { if (current == ' ' || current == '(' || current == ')') {
current = chars[++i]; current = pathFragment.charAt(++i);
continue; continue;
} }
buffer.append(current); buffer.append(current);
current = chars[++i]; current = pathFragment.charAt(++i);
} }
String function = buffer.toString(); String function = buffer.toString();
buffer.setLength(0); buffer.setLength(0);
@ -423,11 +420,11 @@ public class PathCompiler {
} }
while (current != ')') { while (current != ')') {
if (current == ' ') { if (current == ' ') {
current = chars[++i]; current = pathFragment.charAt(++i);
continue; continue;
} }
buffer.append(current); buffer.append(current);
current = chars[++i]; current = pathFragment.charAt(++i);
} }
} else { } else {
@ -442,12 +439,12 @@ public class PathCompiler {
if (buffer.length() == 0) { if (buffer.length() == 0) {
//this is a tail slice [:12] //this is a tail slice [:12]
sliceTo = true; sliceTo = true;
current = chars[++i]; current = pathFragment.charAt(++i);
while (Character.isDigit(current) || current == ' ' || current == '-') { while (Character.isDigit(current) || current == ' ' || current == '-') {
if (current != ' ') { if (current != ' ') {
buffer.append(current); buffer.append(current);
} }
current = chars[++i]; current = pathFragment.charAt(++i);
} }
numbers.add(Integer.parseInt(buffer.toString())); numbers.add(Integer.parseInt(buffer.toString()));
buffer.setLength(0); buffer.setLength(0);
@ -455,14 +452,14 @@ public class PathCompiler {
//we now this starts with [12:??? //we now this starts with [12:???
numbers.add(Integer.parseInt(buffer.toString())); numbers.add(Integer.parseInt(buffer.toString()));
buffer.setLength(0); buffer.setLength(0);
current = chars[++i]; current = pathFragment.charAt(++i);
//this is a tail slice [:12] //this is a tail slice [:12]
while (Character.isDigit(current) || current == ' ' || current == '-') { while (Character.isDigit(current) || current == ' ' || current == '-') {
if (current != ' ') { if (current != ' ') {
buffer.append(current); buffer.append(current);
} }
current = chars[++i]; current = pathFragment.charAt(++i);
} }
if (buffer.length() == 0) { if (buffer.length() == 0) {
@ -486,7 +483,7 @@ public class PathCompiler {
if (current == ']') { if (current == ']') {
break; break;
} }
current = chars[++i]; current = pathFragment.charAt(++i);
} }
} }
if (buffer.length() > 0) { if (buffer.length() > 0) {

14
json-path/src/main/java/com/jayway/jsonpath/internal/compiler/EvaluationContextImpl.java

@ -29,18 +29,18 @@ public class EvaluationContextImpl implements EvaluationContext {
notNull(configuration, "configuration can not be null"); notNull(configuration, "configuration can not be null");
this.path = path; this.path = path;
this.configuration = configuration; this.configuration = configuration;
this.valueResult = configuration.getProvider().createArray(); this.valueResult = configuration.jsonProvider().createArray();
this.pathResult = configuration.getProvider().createArray(); this.pathResult = configuration.jsonProvider().createArray();
} }
public void addResult(String path, Object model) { public void addResult(String path, Object model) {
configuration.getProvider().setProperty(valueResult, resultIndex, model); configuration.jsonProvider().setProperty(valueResult, resultIndex, model);
configuration.getProvider().setProperty(pathResult, resultIndex, path); configuration.jsonProvider().setProperty(pathResult, resultIndex, path);
resultIndex++; resultIndex++;
} }
public JsonProvider jsonProvider() { public JsonProvider jsonProvider() {
return configuration.getProvider(); return configuration.jsonProvider();
} }
public Set<Option> options() { public Set<Option> options() {
@ -62,7 +62,7 @@ public class EvaluationContextImpl implements EvaluationContext {
} }
return (T) jsonProvider().getArrayIndex(valueResult, 0); return (T) jsonProvider().getArrayIndex(valueResult, 0);
} }
return (T) valueResult; return (T)valueResult;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -78,7 +78,7 @@ public class EvaluationContextImpl implements EvaluationContext {
public List<String> getPathList() { public List<String> getPathList() {
List<String> res = new ArrayList<String>(); List<String> res = new ArrayList<String>();
if(resultIndex > 0){ if(resultIndex > 0){
Iterable<Object> objects = configuration.getProvider().toIterable(pathResult); Iterable<?> objects = configuration.jsonProvider().toIterable(pathResult);
for (Object o : objects) { for (Object o : objects) {
res.add((String)o); res.add((String)o);
} }

4
json-path/src/main/java/com/jayway/jsonpath/internal/compiler/PathToken.java

@ -27,7 +27,7 @@ public abstract class PathToken {
if(propertyVal == JsonProvider.UNDEFINED){ if(propertyVal == JsonProvider.UNDEFINED){
if(isLeaf()) { if(isLeaf()) {
if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){ if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){
propertyVal = null; propertyVal = ctx.jsonProvider().createNull();
} else { } else {
if(ctx.options().contains(Option.SUPPRESS_EXCEPTIONS)){ if(ctx.options().contains(Option.SUPPRESS_EXCEPTIONS)){
return; return;
@ -58,7 +58,7 @@ public abstract class PathToken {
Object propertyVal = readObjectProperty(property, model, ctx); Object propertyVal = readObjectProperty(property, model, ctx);
if(propertyVal == JsonProvider.UNDEFINED){ if(propertyVal == JsonProvider.UNDEFINED){
if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){ if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){
propertyVal = null; propertyVal = ctx.jsonProvider().createNull();;
} else { } else {
continue; continue;
} }

2
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)){ } else if (ctx.jsonProvider().isArray(model)){
int idx = 0; int idx = 0;
Iterable<Object> objects = ctx.jsonProvider().toIterable(model); Iterable<?> objects = ctx.jsonProvider().toIterable(model);
for (Object idxModel : objects) { for (Object idxModel : objects) {
if (accept(idxModel, ctx.configuration())) { if (accept(idxModel, ctx.configuration())) {

9
json-path/src/main/java/com/jayway/jsonpath/internal/compiler/ScanPathToken.java

@ -1,11 +1,11 @@
package com.jayway.jsonpath.internal.compiler; package com.jayway.jsonpath.internal.compiler;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import com.jayway.jsonpath.spi.json.JsonProvider;
/** /**
* *
*/ */
@ -55,7 +55,7 @@ public class ScanPathToken extends PathToken {
predicateMatches.put(currentPath, model); predicateMatches.put(currentPath, model);
} }
Iterable<Object> models = ctx.jsonProvider().toIterable(model); Iterable<?> models = ctx.jsonProvider().toIterable(model);
int idx = 0; int idx = 0;
for (Object evalModel : models) { for (Object evalModel : models) {
String evalPath = currentPath + "[" + idx + "]"; String evalPath = currentPath + "[" + idx + "]";
@ -197,8 +197,11 @@ public class ScanPathToken extends PathToken {
@Override @Override
public boolean matches(Object model) { public boolean matches(Object model) {
if(ctx.jsonProvider().isMap(model)){
Collection<String> keys = ctx.jsonProvider().getPropertyKeys(model); Collection<String> keys = ctx.jsonProvider().getPropertyKeys(model);
return keys.containsAll(propertyPathToken.getProperties()); return keys.containsAll(propertyPathToken.getProperties());
} }
return false;
}
} }
} }

40
json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/ConverterBase.java

@ -0,0 +1,40 @@
package com.jayway.jsonpath.internal.spi.converter;
import com.jayway.jsonpath.spi.converter.ConversionException;
import com.jayway.jsonpath.spi.converter.Converter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public abstract class ConverterBase implements Converter{
private final Set<Converter.ConvertiblePair> convertiblePairs = new HashSet<Converter.ConvertiblePair>();
protected void register(Class<?> srcType, Class<?> targetType){
convertiblePairs.add(new ConvertiblePair(srcType, targetType));
}
@Override
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.unmodifiableSet(convertiblePairs);
}
void assertValidConversion(Object src, Class<?> srcType, Class<?> targetType) {
if (src == null) {
return;
}
if (!srcType.isAssignableFrom(src.getClass())) {
throw new ConversionException("Source: " + src.getClass() + " is not assignable from: " + srcType.getName());
}
if(!canConvert(srcType, targetType)){
throw new ConversionException("Can not convert: " + srcType.getName() + " to: " + targetType.getName());
}
}
boolean canConvert(Class<?> srcType, Class<?> targetType){
return convertiblePairs.contains(new Converter.ConvertiblePair(srcType, targetType));
}
}

38
json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/DateConverter.java

@ -0,0 +1,38 @@
package com.jayway.jsonpath.internal.spi.converter;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.spi.converter.ConversionException;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
public class DateConverter extends ConverterBase {
public DateConverter() {
register(Long.class, Date.class);
register(String.class, Date.class);
}
@Override
public Object convert(Object src, Class<?> srcType, Class<?> targetType, Configuration conf) {
assertValidConversion(src, srcType, targetType);
if(src == null){
return null;
}
if(Long.class.isAssignableFrom(srcType)){
return new Date((Long) src);
}
else if(String.class.isAssignableFrom(srcType)){
try {
return DateFormat.getInstance().parse(src.toString());
} catch (ParseException e) {
throw new ConversionException(e);
}
}
throw new ConversionException("Can not convert: " + srcType.getName() + " to: " + targetType.getName());
}
}

66
json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/DefaultConversionProvider.java

@ -0,0 +1,66 @@
package com.jayway.jsonpath.internal.spi.converter;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.spi.converter.ConversionProvider;
import com.jayway.jsonpath.spi.converter.Converter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
public class DefaultConversionProvider implements ConversionProvider {
private static final Logger logger = LoggerFactory.getLogger(DefaultConversionProvider.class);
private HashMap<Class<?>, HashMap<Class<?>, Converter>> converters = new HashMap<Class<?>, HashMap<Class<?>, Converter>>();
public DefaultConversionProvider(){
addConverters(new NumberConverter());
addConverters(new StringConverter());
addConverters(new DateConverter());
try {
Class.forName("com.google.gson.Gson");
addConverters(new GsonConverter());
} catch (ClassNotFoundException e) {
logger.debug("Gson not found on class path. No converters configured.");
}
}
public void addConverters(ConverterBase converter) {
for (Converter.ConvertiblePair convertible : converter.getConvertibleTypes()) {
if(!converters.containsKey(convertible.getTargetType())){
converters.put(convertible.getTargetType(), new HashMap<Class<?>, Converter>());
}
converters.get(convertible.getTargetType()).put(convertible.getSourceType(), converter);
}
}
@Override
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
HashMap<Class<?>, Converter> targetConverters = converters.get(targetType);
return targetConverters != null && targetConverters.containsKey(sourceType);
}
@Override
public <T> T convert(Object source, Class<T> targetType, Configuration configuration) {
if(source == null){
return null;
}
HashMap<Class<?>, Converter> targetConverters = converters.get(targetType);
if(targetConverters != null){
Converter converter = targetConverters.get(source.getClass());
if(converter != null){
return (T)converter.convert(source, source.getClass(), targetType, configuration);
}
converter = targetConverters.get(Object.class);
if(converter != null){
return (T)converter.convert(source, source.getClass(), targetType, configuration);
}
}
return (T)source;
}
}

90
json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/GsonConverter.java

@ -0,0 +1,90 @@
package com.jayway.jsonpath.internal.spi.converter;
import com.google.gson.JsonArray;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.jayway.jsonpath.Configuration;
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.Date;
import java.util.List;
import java.util.Map;
public class GsonConverter extends ConverterBase {
public GsonConverter() {
register(JsonPrimitive.class, Integer.class);
register(JsonPrimitive.class, Long.class);
register(JsonPrimitive.class, Float.class);
register(JsonPrimitive.class, Double.class);
register(JsonPrimitive.class, BigDecimal.class);
register(JsonPrimitive.class, BigInteger.class);
register(JsonPrimitive.class, Date.class);
register(JsonPrimitive.class, String.class);
register(JsonPrimitive.class, Boolean.class);
register(JsonArray.class, List.class);
register(JsonArray.class, Map.class);
}
@Override
public Object convert(Object src, Class<?> srcType, Class<?> targetType, Configuration conf) {
assertValidConversion(src, srcType, targetType);
if (src == null || src.getClass().equals(JsonNull.class)) {
return null;
}
if (JsonPrimitive.class.isAssignableFrom(srcType)) {
JsonPrimitive primitive = (JsonPrimitive) src;
if (targetType.equals(Long.class)) {
return primitive.getAsLong();
} else if (targetType.equals(Integer.class)) {
return primitive.getAsInt();
} else if (targetType.equals(BigInteger.class)) {
return primitive.getAsBigInteger();
} else if (targetType.equals(Byte.class)) {
return primitive.getAsByte();
} else if (targetType.equals(BigDecimal.class)) {
return primitive.getAsBigDecimal();
} else if (targetType.equals(Double.class)) {
return primitive.getAsDouble();
} else if (targetType.equals(Float.class)) {
return primitive.getAsFloat();
} else if (targetType.equals(String.class)) {
return primitive.getAsString();
} 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()){
try {
return DateFormat.getInstance().parse(primitive.getAsString());
} catch (ParseException e) {
throw new ConversionException(e);
}
}
}
} else if (JsonObject.class.isAssignableFrom(srcType)) {
} else if (JsonArray.class.isAssignableFrom(srcType)) {
}
return null;
}
}

130
json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/NumberConverter.java

@ -0,0 +1,130 @@
package com.jayway.jsonpath.internal.spi.converter;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.spi.converter.ConversionException;
import java.math.BigDecimal;
public class NumberConverter extends ConverterBase {
public NumberConverter() {
//to long
register(Integer.class, Long.class);
register(Double.class, Long.class);
register(Float.class, Long.class);
register(BigDecimal.class, Long.class);
register(String.class, Long.class);
//to int
register(Long.class, Integer.class);
register(Double.class, Integer.class);
register(Float.class, Integer.class);
register(BigDecimal.class, Integer.class);
register(String.class, Integer.class);
//to double
register(Long.class, Double.class);
register(Integer.class, Double.class);
register(Float.class, Double.class);
register(BigDecimal.class, Double.class);
register(String.class, Double.class);
//to float
register(Long.class, Float.class);
register(Integer.class, Float.class);
register(Double.class, Float.class);
register(BigDecimal.class, Float.class);
register(String.class, Float.class);
//to BigDecimal
register(Long.class, BigDecimal.class);
register(Integer.class, BigDecimal.class);
register(Double.class, BigDecimal.class);
register(Float.class, BigDecimal.class);
register(String.class, BigDecimal.class);
}
@Override
public Object convert(Object src, Class<?> srcType, Class<?> targetType, Configuration conf) {
assertValidConversion(src, srcType, targetType);
if (src == null) {
return null;
}
//to long
if(targetType.equals(Long.class)) {
if (Integer.class.isAssignableFrom(srcType)) {
return ((Integer) src).longValue();
} else if (Double.class.isAssignableFrom(srcType)) {
return ((Double) src).longValue();
} else if (BigDecimal.class.isAssignableFrom(srcType)) {
return ((BigDecimal) src).longValue();
} else if (Float.class.isAssignableFrom(srcType)) {
return ((Float) src).longValue();
} else if (String.class.isAssignableFrom(srcType)) {
return Long.parseLong(src.toString());
}
}
else if(targetType.equals(Integer.class)) {
//to int
if (Long.class.isAssignableFrom(srcType)) {
return ((Long) src).intValue();
} else if (Double.class.isAssignableFrom(srcType)) {
return ((Double) src).intValue();
} else if (BigDecimal.class.isAssignableFrom(srcType)) {
return ((BigDecimal) src).intValue();
} else if (Float.class.isAssignableFrom(srcType)) {
return ((Float) src).intValue();
} else if (String.class.isAssignableFrom(srcType)) {
return Integer.parseInt(src.toString());
}
}
else if(targetType.equals(Double.class)) {
//to double
if (Long.class.isAssignableFrom(srcType)) {
return ((Long) src).doubleValue();
} else if (Integer.class.isAssignableFrom(srcType)) {
return ((Integer) src).doubleValue();
} else if (BigDecimal.class.isAssignableFrom(srcType)) {
return ((BigDecimal) src).doubleValue();
} else if (Float.class.isAssignableFrom(srcType)) {
return ((Float) src).doubleValue();
} else if (String.class.isAssignableFrom(srcType)) {
return Double.parseDouble(src.toString());
}
}
else if(targetType.equals(Float.class)) {
//to float
if (Long.class.isAssignableFrom(srcType) && targetType.equals(Float.class)) {
return ((Long) src).floatValue();
} else if (Integer.class.isAssignableFrom(srcType) && targetType.equals(Float.class)) {
return ((Integer) src).floatValue();
} else if (BigDecimal.class.isAssignableFrom(srcType) && targetType.equals(Float.class)) {
return ((BigDecimal) src).floatValue();
} else if (Double.class.isAssignableFrom(srcType) && targetType.equals(Float.class)) {
return ((Double) src).floatValue();
} else if (String.class.isAssignableFrom(srcType) && targetType.equals(Float.class)) {
return Float.parseFloat(src.toString());
}
}
else if(targetType.equals(BigDecimal.class)) {
//to BigDecimal
if (Long.class.isAssignableFrom(srcType) && targetType.equals(BigDecimal.class)) {
return new BigDecimal(src.toString());
} else if (Integer.class.isAssignableFrom(srcType) && targetType.equals(BigDecimal.class)) {
return new BigDecimal(src.toString());
} else if (Float.class.isAssignableFrom(srcType) && targetType.equals(BigDecimal.class)) {
return new BigDecimal(src.toString());
} else if (Double.class.isAssignableFrom(srcType) && targetType.equals(BigDecimal.class)) {
return new BigDecimal(src.toString());
} else if (String.class.isAssignableFrom(srcType) && targetType.equals(BigDecimal.class)) {
return new BigDecimal(src.toString());
}
}
throw new ConversionException("Can not convert: " + srcType.getName() + " to: " + targetType.getName());
}
}

25
json-path/src/main/java/com/jayway/jsonpath/internal/spi/converter/StringConverter.java

@ -0,0 +1,25 @@
package com.jayway.jsonpath.internal.spi.converter;
import com.jayway.jsonpath.Configuration;
public class StringConverter extends ConverterBase {
public StringConverter() {
register(Object.class, String.class);
}
@Override
public Object convert(Object src, Class<?> srcType, Class<?> targetType, Configuration conf) {
assertValidConversion(src, srcType, targetType);
if (src == null) {
return null;
}
return src.toString();
}
@Override
boolean canConvert(Class<?> srcType, Class<?> targetType){
return true;
}
}

75
json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/AbstractJsonProvider.java

@ -14,8 +14,12 @@
*/ */
package com.jayway.jsonpath.internal.spi.json; package com.jayway.jsonpath.internal.spi.json;
import com.jayway.jsonpath.ValueCompareException;
import com.jayway.jsonpath.spi.json.JsonProvider; import com.jayway.jsonpath.spi.json.JsonProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -23,6 +27,52 @@ import java.util.Map;
public abstract class AbstractJsonProvider implements JsonProvider { 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;
}
/** /**
* checks if object is an array * checks if object is an array
* *
@ -33,6 +83,10 @@ public abstract class AbstractJsonProvider implements JsonProvider {
return (obj instanceof List); return (obj instanceof List);
} }
public boolean isString(Object obj){
return (obj instanceof String);
}
/** /**
* Extracts a value from an array * Extracts a value from an array
@ -96,20 +150,15 @@ public abstract class AbstractJsonProvider implements JsonProvider {
} }
/** /**
* Returns the keys from the given object or the indexes from an array * Returns the keys from the given object
* *
* @param obj an array or an object * @param obj an object
* @return the keys for an object or the indexes for an array * @return the keys for an object
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Collection<String> getPropertyKeys(Object obj) { public Collection<String> getPropertyKeys(Object obj) {
if (isArray(obj)) { if (isArray(obj)) {
List l = (List) obj; throw new UnsupportedOperationException();
List<String> keys = new ArrayList<String>(l.size());
for (int i = 0; i < l.size(); i++) {
keys.add(String.valueOf(i));
}
return keys;
} else { } else {
return ((Map) obj).keySet(); return ((Map) obj).keySet();
} }
@ -124,8 +173,12 @@ public abstract class AbstractJsonProvider implements JsonProvider {
public int length(Object obj) { public int length(Object obj) {
if (isArray(obj)) { if (isArray(obj)) {
return ((List) obj).size(); return ((List) obj).size();
} } else if (isMap(obj)){
return getPropertyKeys(obj).size(); return getPropertyKeys(obj).size();
} else if(obj instanceof String){
return ((String)obj).length();
}
throw new RuntimeException("length operation can not applied to " + obj!=null?obj.getClass().getName():"null");
} }
/** /**
@ -135,7 +188,7 @@ public abstract class AbstractJsonProvider implements JsonProvider {
* @return the entries for an array or the values for a map * @return the entries for an array or the values for a map
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Iterable<Object> toIterable(Object obj) { public Iterable<? extends Object> toIterable(Object obj) {
if (isArray(obj)) if (isArray(obj))
return ((Iterable) obj); return ((Iterable) obj);
else else

348
json-path/src/main/java/com/jayway/jsonpath/internal/spi/json/GsonProvider.java

@ -0,0 +1,348 @@
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;
import java.util.List;
import java.util.Map;
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();
static {
//ConverterFactory.registerConverter();
}
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;
/*
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()) {
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 unwrapped;
*/
}
private Number unwrapNumber(Number n){
Number unwrapped;
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;
}
return unwrapped;
}
@Override
public Object parse(String json) throws InvalidJsonException {
return parser.parse(json);
}
@Override
public Object parse(InputStream jsonStream) throws InvalidJsonException {
return parser.parse(new InputStreamReader(jsonStream));
}
@Override
public String toJson(Object obj) {
return obj.toString();
}
@Override
public Object createNull(){
return JsonNull.INSTANCE;
}
@Override
public Object createArray() {
return new JsonArray();
}
@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;
}
@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(), createJsonElement(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(createJsonElement(value));
} else {
array.set(index, createJsonElement(value));
}
}
}
@Override
public boolean isMap(Object obj) {
return (obj instanceof JsonObject) ;
}
@Override
public Collection<String> getPropertyKeys(Object obj) {
List<String> keys = new ArrayList<String>();
for (Map.Entry<String, JsonElement> entry : toJsonObject(obj).entrySet()) {
keys.add(entry.getKey());
}
return keys;
}
@Override
public int length(Object obj) {
if (isArray(obj)) {
return toJsonArray(obj).size();
} else if(isMap(obj)){
return toJsonObject(obj).entrySet().size();
} else {
if(obj instanceof JsonElement){
JsonElement element = toJsonElement(obj);
if(element.isJsonPrimitive()){
return element.toString().length();
}
}
}
throw new RuntimeException("length operation can not applied to " + obj!=null?obj.getClass().getName():"null");
}
@Override
public Iterable<?> toIterable(Object obj) {
if (isArray(obj)) {
return toJsonArray(obj);
} else {
List<JsonElement> values = new ArrayList<JsonElement>();
JsonObject jsonObject = toJsonObject(obj);
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
values.add(entry.getValue());
}
return values;
}
}
private JsonElement createJsonElement(Object o) {
return gson.toJsonTree(o);
}
private JsonArray toJsonArray(Object o) {
return (JsonArray) o;
}
private JsonObject toJsonObject(Object o) {
return (JsonObject) o;
}
private JsonElement toJsonElement(Object o) {
return (JsonElement) o;
}
public static class NumberTypeAdapter
implements JsonSerializer<Number>, JsonDeserializer<Number>,
InstanceCreator<Number> {
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;
}
}
}

21
json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConversionException.java

@ -0,0 +1,21 @@
package com.jayway.jsonpath.spi.converter;
public class ConversionException extends RuntimeException {
public ConversionException(String message, Throwable cause) {
super(message, cause);
}
public ConversionException(Throwable cause) {
super(cause);
}
public ConversionException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public ConversionException(String message) {
super(message);
}
}

10
json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConversionProvider.java

@ -0,0 +1,10 @@
package com.jayway.jsonpath.spi.converter;
import com.jayway.jsonpath.Configuration;
public interface ConversionProvider {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
<T> T convert(Object source, Class<T> targetType, Configuration configuration);
}

69
json-path/src/main/java/com/jayway/jsonpath/spi/converter/Converter.java

@ -2,6 +2,71 @@ package com.jayway.jsonpath.spi.converter;
import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.Configuration;
public interface Converter<T>{ import java.util.Set;
T convert(Object o, Configuration conf);
import static com.jayway.jsonpath.internal.Utils.notNull;
public interface Converter {
Set<ConvertiblePair> getConvertibleTypes();
Object convert(Object src, Class<?> srcType, Class<?> targetType, Configuration conf);
/**
* Holder for a source-to-target class pair.
*/
public static final class ConvertiblePair {
private final Class<?> sourceType;
private final Class<?> targetType;
/**
* Create a new source-to-target pair.
*
* @param sourceType the source type
* @param targetType the target type
*/
public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
notNull(sourceType, "Source type must not be null");
notNull(targetType, "Target type must not be null");
this.sourceType = sourceType;
this.targetType = targetType;
}
public Class<?> getSourceType() {
return this.sourceType;
}
public Class<?> getTargetType() {
return this.targetType;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ConvertiblePair)) return false;
ConvertiblePair that = (ConvertiblePair) o;
if (!sourceType.equals(that.sourceType)) return false;
if (!targetType.equals(that.targetType)) return false;
return true;
}
@Override
public int hashCode() {
int result = sourceType.hashCode();
result = 31 * result + targetType.hashCode();
return result;
}
@Override
public String toString() {
return this.sourceType.getName() + " -> " + this.targetType.getName();
}
}
} }

174
json-path/src/main/java/com/jayway/jsonpath/spi/converter/ConverterFactory.java

@ -1,174 +0,0 @@
package com.jayway.jsonpath.spi.converter;
import com.jayway.jsonpath.Configuration;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ConverterFactory {
private static Map<Class<?>, Converter<?>> converters = new ConcurrentHashMap<Class<?>, Converter<?>>();
static {
registerConverter(Long.class, new LongConverter());
registerConverter(Integer.class, new IntegerConverter());
registerConverter(BigDecimal.class, new BigDecimalConverter());
registerConverter(Double.class, new DoubleConverter());
registerConverter(Date.class, new DateConverter());
registerConverter(String.class, new StringConverter());
}
public static <T> Converter<T> createConverter(Class<T> target){
Converter<T> converter = (Converter<T>) converters.get(target);
if(converter == null){
converter = new Converter<T>() {
@Override
public T convert(Object o, Configuration conf) {
return (T)o;
}
};
}
return converter;
}
public static <T> void registerConverter(Class<T> target, Converter<T> converter){
converters.put(target, converter);
}
public static <T> void unRegisterConverter(Class<T> target){
converters.remove(target);
}
private static class StringConverter implements Converter<String> {
@Override
public String convert(Object o, Configuration conf) {
if(o == null){
return null;
} else {
return o.toString();
}
}
}
private static class DateConverter implements Converter<Date> {
@Override
public Date convert(Object o, Configuration conf) {
if(o == null){
return null;
} else if(o instanceof Date){
return (Date)o;
} else if(o instanceof Long){
return new Date(((Long)o).longValue());
} else if(o instanceof String){
try {
return DateFormat.getInstance().parse(o.toString());
} catch (ParseException e) {
throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Integer.class.getName(), e);
}
}
throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Integer.class.getName());
}
}
private static class IntegerConverter implements Converter<Integer> {
@Override
public Integer convert(Object o, Configuration conf) {
if(o == null){
return null;
} else if(o instanceof Integer){
return (Integer)o;
} else if(o instanceof Long){
return ((Long)o).intValue();
} else if(o instanceof Double){
return ((Double)o).intValue();
} else if(o instanceof BigDecimal){
return ((BigDecimal)o).intValue();
} else if(o instanceof Float){
return ((Float)o).intValue();
} else if(o instanceof String){
return Integer.parseInt(o.toString());
}
throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Integer.class.getName());
}
}
private static class LongConverter implements Converter<Long> {
@Override
public Long convert(Object o, Configuration conf) {
if(o == null){
return null;
} else if(o instanceof Long){
return (Long)o;
} else if(o instanceof Integer){
return ((Integer)o).longValue();
} else if(o instanceof Double){
return ((Double)o).longValue();
} else if(o instanceof BigDecimal){
return ((BigDecimal)o).longValue();
} else if(o instanceof Float){
return ((Float)o).longValue();
} else if(o instanceof String){
return Long.parseLong(o.toString());
}
throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Long.class.getName());
}
}
private static class DoubleConverter implements Converter<Double> {
@Override
public Double convert(Object o, Configuration conf) {
if(o == null){
return null;
} else if(o instanceof Double){
return (Double)o;
} else if(o instanceof Integer){
return Double.valueOf(o.toString());
} else if(o instanceof Long){
return Double.valueOf(o.toString());
} else if(o instanceof BigDecimal){
return ((BigDecimal)o).doubleValue();
} else if(o instanceof Float){
return ((Float)o).doubleValue();
} else if(o instanceof String){
return Double.parseDouble(o.toString());
}
throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + Double.class.getName());
}
}
private static class BigDecimalConverter implements Converter<BigDecimal> {
@Override
public BigDecimal convert(Object o, Configuration conf) {
if(o == null){
return null;
} else if(o instanceof BigDecimal){
return (BigDecimal)o;
} else if(o instanceof Integer){
return new BigDecimal(o.toString());
} else if(o instanceof Long){
return new BigDecimal(o.toString());
} else if(o instanceof Float){
return BigDecimal.valueOf(((Float)o).doubleValue());
} else if(o instanceof String){
return new BigDecimal(o.toString());
}
throw new IllegalArgumentException("Can not convert: " + o.getClass().getName() + " to: " + BigDecimal.class.getName());
}
}
}

28
json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java

@ -15,6 +15,7 @@
package com.jayway.jsonpath.spi.json; package com.jayway.jsonpath.spi.json;
import com.jayway.jsonpath.InvalidJsonException; import com.jayway.jsonpath.InvalidJsonException;
import com.jayway.jsonpath.ValueCompareException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
@ -23,12 +24,18 @@ public interface JsonProvider {
static final Object UNDEFINED = new Object(); 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(String json) throws InvalidJsonException;
Object parse(InputStream jsonStream) throws InvalidJsonException; Object parse(InputStream jsonStream) throws InvalidJsonException;
String toJson(Object obj); String toJson(Object obj);
Object createNull();
Object createArray(); Object createArray();
/** /**
@ -40,9 +47,18 @@ public interface JsonProvider {
boolean isArray(Object obj); boolean isArray(Object obj);
/** /**
* Get the length of an array or object * checks if object is a string
* *
* @param obj an array or an object * @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
*
* @param obj an array or object or a string
* @return the number of entries in the array or object * @return the number of entries in the array or object
*/ */
int length(Object obj); int length(Object obj);
@ -53,14 +69,14 @@ public interface JsonProvider {
* @param obj an array or an object * @param obj an array or an object
* @return the entries for an array or the values for a map * @return the entries for an array or the values for a map
*/ */
Iterable<Object> toIterable(Object obj); Iterable<?> toIterable(Object obj);
/** /**
* Returns the keys from the given object or the indexes from an array * Returns the keys from the given object
* *
* @param obj an array or an object * @param obj an object
* @return the keys for an object or the indexes for an array * @return the keys for an object
*/ */
Collection<String> getPropertyKeys(Object obj); Collection<String> getPropertyKeys(Object obj);

31
json-path/src/test/java/com/jayway/jsonpath/BaseTest.java

@ -1,6 +1,37 @@
package com.jayway.jsonpath; package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.spi.converter.DefaultConversionProvider;
import com.jayway.jsonpath.internal.spi.json.GsonProvider;
import com.jayway.jsonpath.spi.converter.ConversionProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.EnumSet;
import java.util.Set;
public class BaseTest { public class BaseTest {
/*
static {
Configuration.setDefaults(new Configuration.Defaults() {
@Override
public JsonProvider jsonProvider() {
return new GsonProvider();
}
@Override
public Set<Option> options() {
return EnumSet.noneOf(Option.class);
}
@Override
public ConversionProvider conversionProvider() {
return new DefaultConversionProvider();
}
});
}
*/
public static final String JSON_DOCUMENT = "{\n" + public static final String JSON_DOCUMENT = "{\n" +
" \"string-property\" : \"string-value\", \n" + " \"string-property\" : \"string-value\", \n" +

19
json-path/src/test/java/com/jayway/jsonpath/ConverterTest.java

@ -1,9 +1,15 @@
package com.jayway.jsonpath; package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.spi.converter.DefaultConversionProvider;
import com.jayway.jsonpath.internal.spi.json.GsonProvider;
import com.jayway.jsonpath.spi.converter.ConversionProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import org.junit.Test; import org.junit.Test;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Date; import java.util.Date;
import java.util.EnumSet;
import java.util.Set;
import static com.jayway.jsonpath.JsonPath.parse; import static com.jayway.jsonpath.JsonPath.parse;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
@ -11,35 +17,36 @@ import static org.assertj.core.api.Assertions.assertThat;
public class ConverterTest extends BaseTest { public class ConverterTest extends BaseTest {
@Test @Test
public void an_Integer_can_be_converted_to_a_Long() { public void an_Integer_can_be_converted_to_a_Long() {
assertThat(parse(singletonMap("val", 1)).read("val", Long.class)).isEqualTo(1L); assertThat(parse("{\"val\": 1}").read("val", Long.class)).isEqualTo(1L);
} }
@Test @Test
public void an_String_can_be_converted_to_a_Long() { public void an_String_can_be_converted_to_a_Long() {
assertThat(parse(singletonMap("val", "1")).read("val", Long.class)).isEqualTo(1L); assertThat(parse("{\"val\": 1}").read("val", Long.class)).isEqualTo(1L);
} }
@Test @Test
public void an_Integer_can_be_converted_to_a_String() { public void an_Integer_can_be_converted_to_a_String() {
assertThat(parse(singletonMap("val", 1)).read("val", String.class)).isEqualTo("1"); assertThat(parse("{\"val\": 1}").read("val", String.class)).isEqualTo("1");
} }
@Test @Test
public void an_Integer_can_be_converted_to_a_Double() { public void an_Integer_can_be_converted_to_a_Double() {
assertThat(parse(singletonMap("val", 1)).read("val", Double.class)).isEqualTo(1D); assertThat(parse("{\"val\": 1}").read("val", Double.class)).isEqualTo(1D);
} }
@Test @Test
public void a_BigDecimal_can_be_converted_to_a_Long() { public void a_BigDecimal_can_be_converted_to_a_Long() {
assertThat(parse(singletonMap("val", new BigDecimal(1.5D))).read("val", Long.class)).isEqualTo(1L); assertThat(parse("{\"val\": 1.5}").read("val", Long.class)).isEqualTo(1L);
} }
@Test @Test
public void a_Long_can_be_converted_to_a_Date() { public void a_Long_can_be_converted_to_a_Date() {
Date now = new Date(); Date now = new Date();
assertThat(parse(singletonMap("val", now.getTime())).read("val", Date.class)).isEqualTo(now); assertThat(parse("{\"val\": "+now.getTime()+"}").read("val", Date.class)).isEqualTo(now);
} }
} }

4
json-path/src/test/java/com/jayway/jsonpath/FilterTest.java

@ -12,8 +12,8 @@ import static org.assertj.core.api.Assertions.assertThat;
public class FilterTest extends BaseTest { public class FilterTest extends BaseTest {
Configuration conf = Configuration.defaultConfiguration();
Object json = conf.getProvider().parse( Object json = Configuration.defaultConfiguration().jsonProvider().parse(
"{" + "{" +
" \"int-key\" : 1, " + " \"int-key\" : 1, " +
" \"long-key\" : 3000000000, " + " \"long-key\" : 3000000000, " +

12
json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java

@ -20,7 +20,7 @@ public class OptionsTest extends BaseTest {
Configuration conf = Configuration.defaultConfiguration(); Configuration conf = Configuration.defaultConfiguration();
assertThat(using(conf).parse(singletonMap("foo", "bar")).read("$.baz")).isNull(); assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.baz")).isNull();
} }
@Test @Test
@ -28,7 +28,7 @@ public class OptionsTest extends BaseTest {
Configuration conf = Configuration.builder().options(DEFAULT_PATH_LEAF_TO_NULL).build(); Configuration conf = Configuration.builder().options(DEFAULT_PATH_LEAF_TO_NULL).build();
assertThat(using(conf).parse(singletonMap("foo", "bar")).read("$.baz")).isNull(); assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.baz", Object.class)).isNull();
} }
@Test @Test
@ -36,7 +36,7 @@ public class OptionsTest extends BaseTest {
Configuration conf = Configuration.defaultConfiguration(); Configuration conf = Configuration.defaultConfiguration();
assertThat(using(conf).parse(singletonMap("foo", "bar")).read("$.foo")).isInstanceOf(String.class); assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isInstanceOf(String.class);
} }
@Test @Test
@ -44,21 +44,21 @@ public class OptionsTest extends BaseTest {
Configuration conf = Configuration.builder().options(ALWAYS_RETURN_LIST).build(); Configuration conf = Configuration.builder().options(ALWAYS_RETURN_LIST).build();
assertThat(using(conf).parse(singletonMap("foo", "bar")).read("$.foo")).isInstanceOf(List.class); assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isInstanceOf(List.class);
} }
@Test @Test
public void a_path_evaluation_is_returned_as_VALUE_by_default() { public void a_path_evaluation_is_returned_as_VALUE_by_default() {
Configuration conf = Configuration.defaultConfiguration(); Configuration conf = Configuration.defaultConfiguration();
assertThat(using(conf).parse(singletonMap("foo", "bar")).read("$.foo")).isEqualTo("bar"); assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isEqualTo("bar");
} }
@Test @Test
public void a_path_evaluation_can_be_returned_as_PATH_LIST() { public void a_path_evaluation_can_be_returned_as_PATH_LIST() {
Configuration conf = Configuration.builder().options(AS_PATH_LIST).build(); Configuration conf = Configuration.builder().options(AS_PATH_LIST).build();
List<String> pathList = using(conf).parse(singletonMap("foo", "bar")).read("$.foo"); List<String> pathList = using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo");
assertThat(pathList).containsOnly("$['foo']"); assertThat(pathList).containsOnly("$['foo']");
} }

10
json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java

@ -10,6 +10,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@SuppressWarnings("ALL") @SuppressWarnings("ALL")
public class ReturnTypeTest extends BaseTest { public class ReturnTypeTest extends BaseTest {
private static ReadContext reader = JsonPath.parse(JSON_DOCUMENT); private static ReadContext reader = JsonPath.parse(JSON_DOCUMENT);
@Test @Test
@ -19,7 +20,7 @@ public class ReturnTypeTest extends BaseTest {
@Test @Test
public void assert_ints_can_be_read() { public void assert_ints_can_be_read() {
assertThat(reader.read("$.int-max-property")).isEqualTo(Integer.MAX_VALUE); assertThat(reader.read("$.int-max-property", Integer.class)).isEqualTo(Integer.MAX_VALUE);
} }
@Test @Test
@ -39,6 +40,13 @@ public class ReturnTypeTest extends BaseTest {
@Test @Test
public void assert_arrays_can_be_read() { public void assert_arrays_can_be_read() {
/*
Object result = reader.read("$.store.book");
assertThat(reader.configuration().jsonProvider().isArray(result)).isTrue();
assertThat(reader.configuration().jsonProvider().length(result)).isEqualTo(4);
*/
assertThat(reader.read("$.store.book", List.class)).hasSize(4); assertThat(reader.read("$.store.book", List.class)).hasSize(4);
} }

2
json-path/src/test/java/com/jayway/jsonpath/old/FilterTest.java

@ -347,7 +347,7 @@ public class FilterTest extends BaseTest {
Predicate customFilter = new Predicate () { Predicate customFilter = new Predicate () {
@Override @Override
public boolean apply(PredicateContext ctx) { public boolean apply(PredicateContext ctx) {
if (ctx.configuration().getProvider().getMapValue(ctx.target(), "name").equals("rootGrandChild_A")) { if (ctx.configuration().jsonProvider().getMapValue(ctx.target(), "name").equals("rootGrandChild_A")) {
return true; return true;
} }
return false; return false;

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

@ -1,5 +1,6 @@
package com.jayway.jsonpath.old; package com.jayway.jsonpath.old;
import com.jayway.jsonpath.BaseTest;
import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException; import com.jayway.jsonpath.PathNotFoundException;
@ -16,7 +17,7 @@ import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class JsonPathTest { public class JsonPathTest extends BaseTest {
static { static {
@ -61,7 +62,7 @@ public class JsonPathTest {
" }\n" + " }\n" +
"}"; "}";
public final static Object OBJ_DOCUMENT = new JsonSmartJsonProvider().parse(DOCUMENT); public final static Object OBJ_DOCUMENT = JsonPath.parse(DOCUMENT).json();
private final static String PRODUCT_JSON = "{\n" + private final static String PRODUCT_JSON = "{\n" +

3
json-path/src/test/java/com/jayway/jsonpath/old/internal/ScanPathTokenTest.java

@ -5,6 +5,7 @@ import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.internal.PathCompiler; import com.jayway.jsonpath.internal.PathCompiler;
import com.jayway.jsonpath.internal.spi.json.JsonSmartJsonProvider; import com.jayway.jsonpath.internal.spi.json.JsonSmartJsonProvider;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;
@ -91,6 +92,8 @@ public class ScanPathTokenTest {
@Test @Test
@Ignore("does not work currently")
//FIXME handle $.. like the Goessner implementation
public void a_root_scan() { public void a_root_scan() {
Object o = JsonPath.read(DOCUMENT, "$.."); Object o = JsonPath.read(DOCUMENT, "$..");

7
pom.xml

@ -182,6 +182,13 @@
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version> <version>${jackson.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3</version>
</dependency>
<dependency> <dependency>
<groupId>io.fastjson</groupId> <groupId>io.fastjson</groupId>
<artifactId>boon</artifactId> <artifactId>boon</artifactId>

2
system.properties

@ -1 +1 @@
java.runtime.version=1.7 java.runtime.version=1.6
Loading…
Cancel
Save