From 1735bc7a876128644c04c655e48a4b21277cef83 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Wed, 18 Mar 2015 23:09:44 +0100 Subject: [PATCH] Removed deprecated classes and some minor fixes. --- changelog.md | 9 +- .../java/com/jayway/jsonpath/Criteria.java | 267 ++++++++++-------- .../java/com/jayway/jsonpath/JsonPath.java | 24 -- .../com/jayway/jsonpath/ParseContext.java | 3 - .../java/com/jayway/jsonpath/ReadContext.java | 7 + .../com/jayway/jsonpath/WriteContext.java | 7 + .../jayway/jsonpath/internal/JsonReader.java | 14 +- .../jsonpath/spi/http/HttpProvider.java | 26 -- .../spi/http/HttpProviderFactory.java | 45 --- .../spi/json/JacksonJsonNodeJsonProvider.java | 2 +- .../spi/json/JsonSmartJsonProvider.java | 5 - .../com/jayway/jsonpath/spi/json/Mode.java | 44 --- .../java/com/jayway/jsonpath/BaseTest.java | 7 + .../com/jayway/jsonpath/ReadContextTest.java | 26 ++ .../jayway/jsonpath/old/ComplianceTest.java | 4 +- .../com/jayway/jsonpath/old/FilterTest.java | 76 ++++- .../com/jayway/jsonpath/old/IssuesTest.java | 103 +++++-- .../test/resources/simplelogger.properties | 1 + 18 files changed, 364 insertions(+), 306 deletions(-) delete mode 100644 json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProvider.java delete mode 100644 json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProviderFactory.java delete mode 100644 json-path/src/main/java/com/jayway/jsonpath/spi/json/Mode.java create mode 100644 json-path/src/test/java/com/jayway/jsonpath/ReadContextTest.java diff --git a/changelog.md b/changelog.md index b7a22fef..60c20363 100644 --- a/changelog.md +++ b/changelog.md @@ -1,11 +1,16 @@ -In The Pipe +In the Pipe =========== + +2.0.0 (2015-03-) +================ * Upgraded dependency versions * Moved JsonProvider and MappingProvider implementations out of the interal package **OSGi** -* Deprecated HTTP provider and methods +* Removed HTTP provider and methods * Add an unwrap(Object) method to JsonProvider, use it when extracting values for Criteria evaluation **breaks JsonProvider SPI** * Fixed issue #71 - esacpe character in inline predicates `JsonPath.read(json, "$.logs[?(@.message == 'it\\'s here')].message");` +* New method `jsonString()` added to `ReadContext` and `WriteContext` to extract json model as a string +* Path does not have to be definite in filter API `filter(where("authors[*].lastName").contains("Waugh"))` 1.2.0 (2014-11-11) ================== 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 135a8c51..67a95f16 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java @@ -58,9 +58,9 @@ public class Criteria implements Predicate { private static enum CriteriaType { EQ { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - boolean res = (0 == safeCompare(left, right)); - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), left, res); + boolean eval(Object expected, Object model, PredicateContext ctx) { + boolean res = (0 == safeCompare(expected, model)); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); return res; } @@ -71,9 +71,9 @@ public class Criteria implements Predicate { }, NE { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - boolean res = (0 != safeCompare(left, right)); - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), left, res); + boolean eval(Object expected, Object model, PredicateContext ctx) { + boolean res = (0 != safeCompare(expected, model)); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); return res; } @@ -84,14 +84,15 @@ public class Criteria implements Predicate { }, GT { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - if ((left == null) ^ (right == null)) { + boolean eval(Object expected, Object model, PredicateContext ctx) { + if ((expected == null) ^ (model == null)) { return false; } - boolean res = (0 > safeCompare(left, right)); - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), left, res); + boolean res = (0 > safeCompare(expected, model)); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); return res; } + @Override public String toString() { return ">"; @@ -99,14 +100,15 @@ public class Criteria implements Predicate { }, GTE { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - if ((left == null) ^ (right == null)) { + boolean eval(Object expected, Object model, PredicateContext ctx) { + if ((expected == null) ^ (model == null)) { return false; } - boolean res = (0 >= safeCompare(left, right)); - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), left, res); + boolean res = (0 >= safeCompare(expected, model)); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); return res; } + @Override public String toString() { return ">="; @@ -114,14 +116,15 @@ public class Criteria implements Predicate { }, LT { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - if ((left == null) ^ (right == null)) { + boolean eval(Object expected, Object model, PredicateContext ctx) { + if ((expected == null) ^ (model == null)) { return false; } - boolean res = (0 < safeCompare(left, right)); - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), left, res); + boolean res = (0 < safeCompare(expected, model)); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); return res; } + @Override public String toString() { return "<"; @@ -129,14 +132,15 @@ public class Criteria implements Predicate { }, LTE { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - if ((left == null) ^ (right == null)) { + boolean eval(Object expected, Object model, PredicateContext ctx) { + if ((expected == null) ^ (model == null)) { return false; } - boolean res = (0 <= safeCompare(left, right)); - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), left, res); + boolean res = (0 <= safeCompare(expected, model)); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); return res; } + @Override public String toString() { return "<="; @@ -144,37 +148,59 @@ public class Criteria implements Predicate { }, IN { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { + boolean eval(Object expected, Object model, PredicateContext ctx) { boolean res = false; - Collection exps = (Collection) left; + Collection exps = (Collection) expected; for (Object exp : exps) { - if (0 == safeCompare(exp, right)) { + if (0 == safeCompare(exp, model)) { res = true; break; } } - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), join(", ", exps), res); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), join(", ", exps), res); return res; } }, NIN { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - Collection nexps = (Collection) left; - boolean res = !nexps.contains(right); - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right, name(), join(", ", nexps), res); + boolean eval(Object expected, Object model, PredicateContext ctx) { + Collection nexps = (Collection) expected; + boolean res = !nexps.contains(model); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), join(", ", nexps), res); + return res; + } + }, + CONTAINS { + @Override + boolean eval(Object expected, Object model, PredicateContext ctx) { + boolean res = false; + if (ctx.configuration().jsonProvider().isArray(model)) { + for (Object o : ctx.configuration().jsonProvider().toIterable(model)) { + if (expected.equals(o)) { + res = true; + break; + } + } + } else if(model instanceof String){ + if(isNullish(expected) || !(expected instanceof String)){ + res = false; + } else { + res = ((String) model).contains((String)expected); + } + } + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); return res; } }, ALL { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { + boolean eval(Object expected, Object model, PredicateContext ctx) { boolean res = true; - Collection exps = (Collection) left; - if (ctx.configuration().jsonProvider().isArray(right)) { + Collection exps = (Collection) expected; + if (ctx.configuration().jsonProvider().isArray(model)) { for (Object exp : exps) { boolean found = false; - for (Object check : ctx.configuration().jsonProvider().toIterable(right)) { + for (Object check : ctx.configuration().jsonProvider().toIterable(model)) { if (0 == safeCompare(exp, check)) { found = true; break; @@ -185,71 +211,75 @@ public class Criteria implements Predicate { break; } } - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", join(", ", ctx.configuration().jsonProvider().toIterable(right)), name(), join(", ", exps), res); + if (logger.isDebugEnabled()) + logger.debug("[{}] {} [{}] => {}", join(", ", ctx.configuration().jsonProvider().toIterable(model)), name(), join(", ", exps), res); } else { res = false; - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", "", name(), join(", ", exps), res); + if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", "", name(), join(", ", exps), res); } return res; } }, SIZE { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - int size = (Integer) left; + boolean eval(Object expected, Object model, PredicateContext ctx) { + int size = (Integer) expected; boolean res; - if (ctx.configuration().jsonProvider().isArray(right)) { - int length = ctx.configuration().jsonProvider().length(right); + if (ctx.configuration().jsonProvider().isArray(model)) { + int length = ctx.configuration().jsonProvider().length(model); res = (length == size); - if(logger.isDebugEnabled()) logger.debug("Array with size {} {} {} => {}", length, name(), size, res); - } else if (right instanceof String) { - int length = ((String) right).length(); + if (logger.isDebugEnabled()) logger.debug("Array with size {} {} {} => {}", length, name(), size, res); + } else if (model instanceof String) { + int length = ((String) model).length(); res = length == size; - if(logger.isDebugEnabled()) logger.debug("String with length {} {} {} => {}", length, name(), size, res); + if (logger.isDebugEnabled()) logger.debug("String with length {} {} {} => {}", length, name(), size, res); } else { res = false; - if(logger.isDebugEnabled()) logger.debug("{} {} {} => {}", right == null ? "null" : right.getClass().getName(), name(), size, res); + if (logger.isDebugEnabled()) + logger.debug("{} {} {} => {}", model == null ? "null" : model.getClass().getName(), name(), size, res); } return res; } }, EXISTS { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { + boolean eval(Object expected, Object model, PredicateContext ctx) { //This must be handled outside throw new UnsupportedOperationException(); } }, TYPE { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { - final Class expType = (Class) left; - final Class actType = right == null ? null : right.getClass(); + boolean eval(Object expected, Object model, PredicateContext ctx) { + final Class expType = (Class) expected; + final Class actType = model == null ? null : model.getClass(); return actType != null && expType.isAssignableFrom(actType); } }, REGEX { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { + boolean eval(Object expected, Object model, PredicateContext ctx) { boolean res = false; Pattern pattern; - Object target; + Object target; - if(right instanceof Pattern){ - pattern = (Pattern) right; - target = left; + if (model instanceof Pattern) { + pattern = (Pattern) model; + target = expected; } else { - pattern = (Pattern) left; - target = right; + pattern = (Pattern) expected; + target = model; } - if(target != null){ + if (target != null) { res = pattern.matcher(target.toString()).matches(); } - if(logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", right == null?"null":right.toString(), name(), left==null?"null":left.toString(), res); + if (logger.isDebugEnabled()) + logger.debug("[{}] {} [{}] => {}", model == null ? "null" : model.toString(), name(), expected == null ? "null" : expected.toString(), res); return res; } + @Override public String toString() { return "=~"; @@ -257,32 +287,32 @@ public class Criteria implements Predicate { }, MATCHES { @Override - boolean eval(Object left, final Object right, final PredicateContext ctx) { + boolean eval(Object expected, final Object model, final PredicateContext ctx) { PredicateContextImpl pci = (PredicateContextImpl) ctx; - Predicate exp = (Predicate) left; - return exp.apply(new PredicateContextImpl(right, ctx.root(), ctx.configuration(), pci.documentPathCache())); + Predicate exp = (Predicate) expected; + return exp.apply(new PredicateContextImpl(model, ctx.root(), ctx.configuration(), pci.documentPathCache())); } }, NOT_EMPTY { @Override - boolean eval(Object left, Object right, PredicateContext ctx) { + boolean eval(Object expected, Object model, PredicateContext ctx) { boolean res = false; - if (right != null) { - if (ctx.configuration().jsonProvider().isArray(right)) { - int len = ctx.configuration().jsonProvider().length(right); + if (model != null) { + if (ctx.configuration().jsonProvider().isArray(model)) { + int len = ctx.configuration().jsonProvider().length(model); res = (0 != len); - if(logger.isDebugEnabled()) logger.debug("array length = {} {} => {}", len, name(), res); - } else if (right instanceof String) { - int len = ((String) right).length(); + if (logger.isDebugEnabled()) logger.debug("array length = {} {} => {}", len, name(), res); + } else if (model instanceof String) { + int len = ((String) model).length(); res = (0 != len); - if(logger.isDebugEnabled()) logger.debug("string length = {} {} => {}", len, name(), res); + if (logger.isDebugEnabled()) logger.debug("string length = {} {} => {}", len, name(), res); } } return res; } }; - abstract boolean eval(Object left, Object right, PredicateContext ctx); + abstract boolean eval(Object expected, Object model, PredicateContext ctx); public static CriteriaType parse(String str) { if ("==".equals(str)) { @@ -306,12 +336,12 @@ public class Criteria implements Predicate { } private Criteria(List criteriaChain, Object left) { - + /* if(left instanceof Path) { if (!((Path)left).isDefinite()) { throw new InvalidCriteriaException("A criteria path must be definite. The path " + left.toString() + " is not!"); } - } + }*/ this.left = left; this.criteriaChain = criteriaChain; this.criteriaChain.add(this); @@ -338,17 +368,17 @@ public class Criteria implements Predicate { return true; } - private Object evaluateIfPath(Object target, PredicateContext ctx){ + private Object evaluateIfPath(Object target, PredicateContext ctx) { Object res = target; - if(res instanceof Path){ + if (res instanceof Path) { Path leftPath = (Path) target; - if(ctx instanceof PredicateContextImpl){ + if (ctx instanceof PredicateContextImpl) { //This will use cache for document ($) queries PredicateContextImpl ctxi = (PredicateContextImpl) ctx; res = ctxi.evaluate(leftPath); } else { - Object doc = leftPath.isRootPath()?ctx.root():ctx.item(); + Object doc = leftPath.isRootPath() ? ctx.root() : ctx.item(); res = leftPath.evaluate(doc, ctx.root(), ctx.configuration()).getValue(); } } @@ -361,8 +391,8 @@ public class Criteria implements Predicate { try { Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options(Option.REQUIRE_PROPERTIES).build(); Object value = ((Path) left).evaluate(ctx.item(), ctx.root(), c).getValue(); - if(exists){ - return (value != null); + if (exists) { + return (value != null); } else { return (value == null); } @@ -403,7 +433,7 @@ public class Criteria implements Predicate { */ public static Criteria where(String key) { - if(!key.startsWith("$") && !key.startsWith("@")){ + if (!key.startsWith("$") && !key.startsWith("@")) { key = "@." + key; } return where(PathCompiler.compile(key)); @@ -416,7 +446,7 @@ public class Criteria implements Predicate { * @return the criteria builder */ public Criteria and(String key) { - if(!key.startsWith("$") && !key.startsWith("@")){ + if (!key.startsWith("$") && !key.startsWith("@")) { key = "@." + key; } return new Criteria(this.criteriaChain, PathCompiler.compile(key)); @@ -542,6 +572,19 @@ public class Criteria implements Predicate { return this; } + /** + * The contains operator asserts that the provided object is contained + * in the result. The object that should contain the input can be either an object or a String. + * + * @param o that should exists in given collection or + * @return the criteria + */ + public Criteria contains(Object o) { + this.criteriaType = CriteriaType.CONTAINS; + this.right = o; + return this; + } + /** * The nin operator is similar to $in except that it selects objects for * which the specified field does not have any value in the specified array. @@ -658,15 +701,16 @@ public class Criteria implements Predicate { return this; } - private static boolean isPath(String string){ - return (string != null - && (string.startsWith("$") || string.startsWith("@") || string.startsWith("!@"))); + private static boolean isPath(String string) { + return (string != null + && (string.startsWith("$") || string.startsWith("@") || string.startsWith("!@"))); } - private static boolean isString(String string){ + private static boolean isString(String string) { return (string != null && !string.isEmpty() && string.charAt(0) == '\'' && string.charAt(string.length() - 1) == '\''); } - private static boolean isPattern(String string){ + + private static boolean isPattern(String string) { return (string != null && !string.isEmpty() && string.charAt(0) == '/' @@ -684,13 +728,13 @@ public class Criteria implements Predicate { } - /** * Parse the provided criteria + * * @param criteria * @return a criteria */ - public static Criteria parse(String criteria){ + public static Criteria parse(String criteria) { int operatorIndex = -1; String left = ""; String operator = ""; @@ -713,9 +757,10 @@ public class Criteria implements Predicate { /** * Creates a new criteria - * @param left path to evaluate in criteria + * + * @param left path to evaluate in criteria * @param operator operator - * @param right expected value + * @param right expected value * @return a new Criteria */ public static Criteria create(String left, String operator, String right) { @@ -725,38 +770,38 @@ public class Criteria implements Predicate { Path rightPath = null; boolean existsCheck = true; - if(isPath(left)){ - if(left.charAt(0) == '!'){ + if (isPath(left)) { + if (left.charAt(0) == '!') { existsCheck = false; left = left.substring(1); } leftPath = PathCompiler.compile(left); - if(!leftPath.isDefinite()){ + if (!leftPath.isDefinite()) { throw new InvalidPathException("the predicate path: " + left + " is not definite"); } leftPrepared = leftPath; - } else if(isString(left)) { + } else if (isString(left)) { leftPrepared = left.substring(1, left.length() - 1); - } else if(isPattern(left)){ + } else if (isPattern(left)) { leftPrepared = compilePattern(left); } - if(isPath(right)){ - if(right.charAt(0) == '!'){ + if (isPath(right)) { + if (right.charAt(0) == '!') { throw new InvalidPathException("Invalid negation! Can only be used for existence check e.g [?(!@.foo)]"); } rightPath = PathCompiler.compile(right); - if(!rightPath.isDefinite()){ + if (!rightPath.isDefinite()) { throw new InvalidPathException("the predicate path: " + right + " is not definite"); } rightPrepared = rightPath; - } else if(isString(right)) { + } else if (isString(right)) { rightPrepared = right.substring(1, right.length() - 1); - } else if(isPattern(right)){ + } else if (isPattern(right)) { rightPrepared = compilePattern(right); } - if(leftPath != null && operator.isEmpty()){ + if (leftPath != null && operator.isEmpty()) { return Criteria.where(leftPath).exists(existsCheck); } else { return new Criteria(leftPrepared, CriteriaType.parse(operator), rightPrepared); @@ -765,7 +810,7 @@ public class Criteria implements Predicate { private static int safeCompare(Object left, Object right) throws ValueCompareException { - if(left == right){ + if (left == right) { return 0; } @@ -779,10 +824,10 @@ public class Criteria implements Predicate { } else if (leftNullish && rightNullish) { return 0; } else if (left instanceof String && right instanceof String) { - String exp = (String)left; - if(exp.contains("\'")){ - exp = exp.replace("\\'", "'"); - } + String exp = (String) left; + if (exp.contains("\'")) { + exp = exp.replace("\\'", "'"); + } return exp.compareTo((String) right); } else if (left instanceof Number && right instanceof Number) { return new BigDecimal(left.toString()).compareTo(new BigDecimal(right.toString())); @@ -807,24 +852,20 @@ public class Criteria implements Predicate { } - @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(left.toString()) - //.append("|") .append(criteriaType.toString()) - //.append("|") .append(wrapString(right)); - //.append("|"); return sb.toString(); } - private static String wrapString(Object o){ - if(o == null){ + private static String wrapString(Object o) { + if (o == null) { return "null"; } - if(o instanceof String){ + if (o instanceof String) { return "'" + o.toString() + "'"; } else { return o.toString(); @@ -832,6 +873,4 @@ public class Criteria implements Predicate { } - - } diff --git a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java index 541e9ade..b46af94e 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -21,7 +21,6 @@ import com.jayway.jsonpath.internal.Path; import com.jayway.jsonpath.internal.PathCompiler; import com.jayway.jsonpath.internal.PathRef; import com.jayway.jsonpath.internal.Utils; -import com.jayway.jsonpath.spi.http.HttpProviderFactory; import com.jayway.jsonpath.spi.json.JsonProvider; import java.io.File; @@ -318,29 +317,6 @@ public class JsonPath { return read(jsonURL, Configuration.defaultConfiguration()); } - /** - * Applies this JsonPath to the provided json URL - * - * @param jsonURL url to read from - * @param configuration configuration to use - * @param expected return type - * @return list of objects matched by the given path - * @throws IOException - */ - @SuppressWarnings({"unchecked"}) - public T read(URL jsonURL, Configuration configuration) throws IOException { - notNull(jsonURL, "json URL can not be null"); - notNull(configuration, "jsonProvider can not be null"); - - InputStream in = null; - try { - in = HttpProviderFactory.getProvider().get(jsonURL); - return read(in, "UTF-8", configuration); - } finally { - Utils.closeQuietly(in); - } - } - /** * Applies this JsonPath to the provided json file * diff --git a/json-path/src/main/java/com/jayway/jsonpath/ParseContext.java b/json-path/src/main/java/com/jayway/jsonpath/ParseContext.java index 12f3a34f..16000b3e 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/ParseContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/ParseContext.java @@ -30,7 +30,4 @@ public interface ParseContext { DocumentContext parse(InputStream json, String charset); DocumentContext parse(File json) throws IOException; - - @Deprecated - DocumentContext parse(URL json) throws IOException; } diff --git a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java index 3b6d55f1..45bbd8c8 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/ReadContext.java @@ -30,6 +30,13 @@ public interface ReadContext { */ T json(); + /** + * Returns the JSON model that this context is operating on as a JSON string + * + * @return json model as string + */ + String jsonString(); + /** * Reads the given path from this context * diff --git a/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java b/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java index 1b254da7..0f827895 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/WriteContext.java @@ -30,6 +30,13 @@ public interface WriteContext { */ T json(); + /** + * Returns the JSON model that this context is operating on as a JSON string + * + * @return json model as string + */ + String jsonString(); + /** * Set the value a the given path * diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java index 0371d088..7f207802 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonReader.java @@ -23,7 +23,6 @@ import com.jayway.jsonpath.ParseContext; import com.jayway.jsonpath.Predicate; import com.jayway.jsonpath.ReadContext; import com.jayway.jsonpath.TypeRef; -import com.jayway.jsonpath.spi.http.HttpProviderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +30,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.util.List; import static com.jayway.jsonpath.JsonPath.compile; @@ -111,13 +109,6 @@ public class JsonReader implements ParseContext, DocumentContext { return this; } - @Override - public DocumentContext parse(URL json) throws IOException { - notNull(json, "json url can not be null"); - InputStream is = HttpProviderFactory.getProvider().get(json); - return parse(is); - } - @Override public Configuration configuration() { return configuration; @@ -133,6 +124,11 @@ public class JsonReader implements ParseContext, DocumentContext { return json; } + @Override + public String jsonString() { + return configuration.jsonProvider().toJson(json); + } + @Override public T read(String path, Predicate... filters) { notEmpty(path, "path can not be null or empty"); diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProvider.java deleted file mode 100644 index 403afd99..00000000 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProvider.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2011 the original author or authors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jayway.jsonpath.spi.http; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -@Deprecated -public interface HttpProvider { - - InputStream get(URL url) throws IOException; - -} diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProviderFactory.java b/json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProviderFactory.java deleted file mode 100644 index d3704dab..00000000 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/http/HttpProviderFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2011 the original author or authors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jayway.jsonpath.spi.http; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLConnection; - -@Deprecated -public abstract class HttpProviderFactory { - - public static HttpProviderFactory factory = new HttpProviderFactory() { - @Override - protected HttpProvider create() { - return new HttpProvider() { - @Override - public InputStream get(URL url) throws IOException { - URLConnection connection = url.openConnection(); - connection.setRequestProperty("Accept", "application/json"); - return connection.getInputStream(); - } - }; - } - }; - - public static HttpProvider getProvider() { - return factory.create(); - } - - - protected abstract HttpProvider create(); -} diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java index 382e47af..8ef4cd18 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java @@ -71,7 +71,7 @@ public class JacksonJsonNodeJsonProvider extends AbstractJsonProvider { if (!(obj instanceof JsonNode)) { throw new JsonPathException("Not a JSON Node"); } - return toString(); + return obj.toString(); } @Override diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonSmartJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonSmartJsonProvider.java index e6c54b8c..66172c5e 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonSmartJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonSmartJsonProvider.java @@ -49,11 +49,6 @@ public class JsonSmartJsonProvider extends AbstractJsonProvider { this.mapper = mapper; } - @Deprecated - public JsonSmartJsonProvider(Mode mode) { - this(mode.intValue(), JSONValue.defaultReader.DEFAULT_ORDERED); - } - public Object createArray() { return mapper.createArray(); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/Mode.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/Mode.java deleted file mode 100644 index 4fc45982..00000000 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/Mode.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2011 the original author or authors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.jayway.jsonpath.spi.json; - -@Deprecated -public enum Mode { - - SLACK(-1), - STRICT(1); - - private final int mode; - - Mode(int mode) { - this.mode = mode; - } - - public int intValue() { - return mode; - } - - public Mode parse(int mode) { - if (mode == -1) { - return SLACK; - } else if (mode == 1) { - return STRICT; - } else { - throw new IllegalArgumentException("Mode " + mode + " not supported"); - } - } - - -} 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 8070b04d..21fa0e53 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/BaseTest.java @@ -32,6 +32,13 @@ public class BaseTest { public static final Configuration JSON_SMART_CONFIGURATION = Configuration.defaultConfiguration(); + public static final String JSON_BOOK_DOCUMENT = + "{ " + + " \"category\" : \"reference\",\n" + + " \"author\" : \"Nigel Rees\",\n" + + " \"title\" : \"Sayings of the Century\",\n" + + " \"display-price\" : 8.95\n" + + "}"; public static final String JSON_DOCUMENT = "{\n" + " \"string-property\" : \"string-value\", \n" + " \"int-max-property\" : " + Integer.MAX_VALUE + ", \n" + diff --git a/json-path/src/test/java/com/jayway/jsonpath/ReadContextTest.java b/json-path/src/test/java/com/jayway/jsonpath/ReadContextTest.java new file mode 100644 index 00000000..9e430a07 --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/ReadContextTest.java @@ -0,0 +1,26 @@ +package com.jayway.jsonpath; + +import org.assertj.core.api.Assertions; +import org.junit.Test; + +import static com.jayway.jsonpath.JsonPath.using; + +public class ReadContextTest extends BaseTest { + + @Test + public void json_can_be_fetched_as_string() { + + String expected = "{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"display-price\":8.95}"; + + String jsonString1 = using(JSON_SMART_CONFIGURATION).parse(JSON_BOOK_DOCUMENT).jsonString(); + String jsonString2 = using(JACKSON_CONFIGURATION).parse(JSON_BOOK_DOCUMENT).jsonString(); + String jsonString3 = using(JACKSON_JSON_NODE_CONFIGURATION).parse(JSON_BOOK_DOCUMENT).jsonString(); + String jsonString4 = using(GSON_CONFIGURATION).parse(JSON_BOOK_DOCUMENT).jsonString(); + + Assertions.assertThat(jsonString1).isEqualTo(expected); + Assertions.assertThat(jsonString2).isEqualTo(expected); + Assertions.assertThat(jsonString3).isEqualTo(expected); + Assertions.assertThat(jsonString4).isEqualTo(expected); + } + +} diff --git a/json-path/src/test/java/com/jayway/jsonpath/old/ComplianceTest.java b/json-path/src/test/java/com/jayway/jsonpath/old/ComplianceTest.java index 1b3cc813..52f3813d 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/old/ComplianceTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/old/ComplianceTest.java @@ -107,10 +107,10 @@ public class ComplianceTest { " }\n" + " }"; - //assertThat(JsonPath.>read(json, "$.menu.items[?(@)]"), Matchers.is(notNullValue())); + assertThat(JsonPath.>read(json, "$.menu.items[?(@)]"), Matchers.is(notNullValue())); assertThat(JsonPath.>read(json, "$.menu.items[?(@ && @.id == 'ViewSVG')].id"), hasItems("ViewSVG")); - //assertThat(JsonPath.>read(json, "$.menu.items[?(@ && @.id && !@.label)].id"), hasItems("?")); //low + assertThat(JsonPath.>read(json, "$.menu.items[?(@ && @.id && !@.label)].id"), hasItems("Open", "Quality", "Pause", "Mute", "Copy", "Help")); //low //assertThat(JsonPath.>read(json, "$.menu.items[?(@ && @.label && /SVG/.test(@.label))].id"), hasItems("?")); //low //assertThat(JsonPath.>read(json, "$.menu.items[?(!@)]"), hasItems("?")); //low //assertThat(JsonPath.>read(json, "$..[0]"), hasItems("?")); //low diff --git a/json-path/src/test/java/com/jayway/jsonpath/old/FilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/old/FilterTest.java index f5ab41da..07d38646 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/old/FilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/old/FilterTest.java @@ -2,11 +2,13 @@ package com.jayway.jsonpath.old; import com.jayway.jsonpath.BaseTest; import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.Criteria; import com.jayway.jsonpath.Filter; import com.jayway.jsonpath.InvalidCriteriaException; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Predicate; import com.jayway.jsonpath.spi.json.JsonProvider; +import org.assertj.core.api.Assertions; import org.junit.Test; import java.util.Collections; @@ -412,10 +414,78 @@ public class FilterTest extends BaseTest { assertEquals(2, result2.size()); } - @Test(expected = InvalidCriteriaException.class) - public void filter_path_must_be_absolute() { + @Test + public void contains_filter_evaluates_on_array() { + - where("$.store.*").size(4); + String json = "{\n" + + "\"store\": {\n" + + " \"book\": [\n" + + " {\n" + + " \"category\": \"reference\",\n" + + " \"authors\" : [\n" + + " {\n" + + " \"firstName\" : \"Nigel\",\n" + + " \"lastName\" : \"Rees\"\n" + + " }\n" + + " ],\n" + + " \"title\": \"Sayings of the Century\",\n" + + " \"price\": 8.95\n" + + " },\n" + + " {\n" + + " \"category\": \"fiction\",\n" + + " \"authors\": [\n" + + " {\n" + + " \"firstName\" : \"Evelyn\",\n" + + " \"lastName\" : \"Waugh\"\n" + + " },\n" + + " {\n" + + " \"firstName\" : \"Another\",\n" + + " \"lastName\" : \"Author\"\n" + + " }\n" + + " ],\n" + + " \"title\": \"Sword of Honour\",\n" + + " \"price\": 12.99\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + + Filter filter = filter(where("authors[*].lastName").contains("Waugh")); + + List result = JsonPath.parse(json).read("$.store.book[?].title", filter); + + Assertions.assertThat(result).containsExactly("Sword of Honour"); } + + @Test + public void contains_filter_evaluates_on_string() { + + + String json = "{\n" + + "\"store\": {\n" + + " \"book\": [\n" + + " {\n" + + " \"category\": \"reference\",\n" + + " \"title\": \"Sayings of the Century\",\n" + + " \"price\": 8.95\n" + + " },\n" + + " {\n" + + " \"category\": \"fiction\",\n" + + " \"title\": \"Sword of Honour\",\n" + + " \"price\": 12.99\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + + Filter filter = filter(where("category").contains("fic")); + + List result = JsonPath.parse(json).read("$.store.book[?].title", filter); + + Assertions.assertThat(result).containsExactly("Sword of Honour"); + } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java b/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java index 2e9d9843..fe6cc9ae 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java @@ -6,6 +6,7 @@ import com.jayway.jsonpath.Filter; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Option; import com.jayway.jsonpath.PathNotFoundException; +import com.jayway.jsonpath.Predicate; import com.jayway.jsonpath.internal.Utils; import com.jayway.jsonpath.spi.json.JsonProvider; import org.assertj.core.api.Assertions; @@ -21,6 +22,7 @@ import static com.jayway.jsonpath.JsonPath.read; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; +import static org.assertj.core.api.Assertions.filter; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -233,6 +235,7 @@ public class IssuesTest { String json = "{\"a\":{\"b\":1,\"c\":2}}"; JsonPath.parse(json, configuration).read("a.d"); } + @Test public void issue_22c() throws Exception { //Configuration configuration = Configuration.builder().build(); @@ -243,7 +246,6 @@ public class IssuesTest { } - @Test public void issue_22b() throws Exception { String json = "{\"a\":[{\"b\":1,\"c\":2},{\"b\":5,\"c\":2}]}"; @@ -270,9 +272,9 @@ public class IssuesTest { assertEquals(1, result.size()); assertEquals("atext2", result.get(0).get("a")); - + } - + @Test public void issue_29_b() throws Exception { String json = "{\"list\": [ { \"a\":\"atext\", \"b\":{ \"b-a\":\"batext\", \"b-b\":\"bbtext\" } }, { \"a\":\"atext2\", \"b\":{ \"b-a\":\"batext2\", \"b-b\":\"bbtext2\" } } ] }"; @@ -280,6 +282,7 @@ public class IssuesTest { assertTrue(result.size() == 1); } + @Test public void issue_30() throws Exception { String json = "{\"foo\" : {\"@id\" : \"123\", \"$\" : \"hello\"}}"; @@ -289,13 +292,13 @@ public class IssuesTest { } @Test - public void issue_32(){ + public void issue_32() { String json = "{\"text\" : \"skill: \\\"Heuristic Evaluation\\\"\", \"country\" : \"\"}"; assertEquals("skill: \"Heuristic Evaluation\"", read(json, "$.text")); } @Test - public void issue_33(){ + public void issue_33() { String json = "{ \"store\": {\n" + " \"book\": [ \n" + " { \"category\": \"reference\",\n" + @@ -343,7 +346,7 @@ public class IssuesTest { @Test(expected = PathNotFoundException.class) public void a_test() { - String json ="{\n" + + String json = "{\n" + " \"success\": true,\n" + " \"data\": {\n" + " \"user\": 3,\n" + @@ -385,7 +388,7 @@ public class IssuesTest { read(json, "nonExistingProperty"); failBecauseExceptionWasNotThrown(PathNotFoundException.class); - } catch (PathNotFoundException e){ + } catch (PathNotFoundException e) { } @@ -394,7 +397,7 @@ public class IssuesTest { read(json, "nonExisting.property"); failBecauseExceptionWasNotThrown(PathNotFoundException.class); - } catch (PathNotFoundException e){ + } catch (PathNotFoundException e) { } } @@ -411,8 +414,6 @@ public class IssuesTest { public void issue_46() { - - String json = "{\"a\": {}}"; Configuration configuration = Configuration.defaultConfiguration().setOptions(Option.SUPPRESS_EXCEPTIONS); @@ -422,7 +423,7 @@ public class IssuesTest { read(json, "a.x"); failBecauseExceptionWasNotThrown(PathNotFoundException.class); - } catch (PathNotFoundException e){ + } catch (PathNotFoundException e) { Assertions.assertThat(e).hasMessage("No results for path: $['a']['x']"); } } @@ -437,7 +438,7 @@ public class IssuesTest { " ]\n" + "}\n"; - List result = JsonPath.read(json, "$.a.*.b.*.c"); + List result = JsonPath.read(json, "$.a.*.b.*.c"); Assertions.assertThat(result).containsExactly("foo"); @@ -447,7 +448,7 @@ public class IssuesTest { public void issue_60() { - String json ="[\n" + + String json = "[\n" + "{\n" + " \"mpTransactionId\": \"542986eae4b001fd500fdc5b-coreDisc_50-title\",\n" + " \"resultType\": \"FAIL\",\n" + @@ -498,19 +499,65 @@ public class IssuesTest { Assertions.assertThat(problems).containsExactly("Chain does not have a discovery event. Possible it was cut by the date that was picked", "No start transcoding events found"); } - @Test - public void issue_71() { - String json = "{\n" - + " \"logs\": [\n" - + " {\n" - + " \"message\": \"it's here\",\n" - + " \"id\": 2\n" - + " }\n" - + " ]\n" - + "}"; - - List result = JsonPath.read(json, "$.logs[?(@.message == 'it\\'s here')].message"); - - Assertions.assertThat(result).containsExactly("it's here"); - } + //http://stackoverflow.com/questions/28596324/jsonpath-filtering-api + @Test + public void stack_overflow_question_1() { + + + String json = "{\n" + + "\"store\": {\n" + + " \"book\": [\n" + + " {\n" + + " \"category\": \"reference\",\n" + + " \"authors\" : [\n" + + " {\n" + + " \"firstName\" : \"Nigel\",\n" + + " \"lastName\" : \"Rees\"\n" + + " }\n" + + " ],\n" + + " \"title\": \"Sayings of the Century\",\n" + + " \"price\": 8.95\n" + + " },\n" + + " {\n" + + " \"category\": \"fiction\",\n" + + " \"authors\": [\n" + + " {\n" + + " \"firstName\" : \"Evelyn\",\n" + + " \"lastName\" : \"Waugh\"\n" + + " },\n" + + " {\n" + + " \"firstName\" : \"Another\",\n" + + " \"lastName\" : \"Author\"\n" + + " }\n" + + " ],\n" + + " \"title\": \"Sword of Honour\",\n" + + " \"price\": 12.99\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + + Filter filter = Filter.filter(Criteria.where("authors[*].lastName").contains("Waugh")); + + Object read = JsonPath.parse(json).read("$.store.book[?]", filter); + + System.out.println(read); + } + + @Test + public void issue_71() { + String json = "{\n" + + " \"logs\": [\n" + + " {\n" + + " \"message\": \"it's here\",\n" + + " \"id\": 2\n" + + " }\n" + + " ]\n" + + "}"; + + List result = JsonPath.read(json, "$.logs[?(@.message == 'it\\'s here')].message"); + + Assertions.assertThat(result).containsExactly("it's here"); + } } diff --git a/json-path/src/test/resources/simplelogger.properties b/json-path/src/test/resources/simplelogger.properties index eddc5f90..6cb420ef 100644 --- a/json-path/src/test/resources/simplelogger.properties +++ b/json-path/src/test/resources/simplelogger.properties @@ -1,2 +1,3 @@ org.slf4j.simpleLogger.log.com.jayway=debug +