diff --git a/Test Results - Tests_in_'json-path-parent_json-path'.html b/Test Results - Tests_in_'json-path-parent_json-path'.html new file mode 100644 index 00000000..150a8221 --- /dev/null +++ b/Test Results - Tests_in_'json-path-parent_json-path'.html @@ -0,0 +1,5817 @@ + + + + + Test Results — Tests in 'json-path-parent.json-path' + + + + + + + + + +
+ +
+ +
+
+ + + diff --git a/Test Results - Tests_in_'json-path-parent_json-path-assert'.html b/Test Results - Tests_in_'json-path-parent_json-path-assert'.html new file mode 100644 index 00000000..48e421c7 --- /dev/null +++ b/Test Results - Tests_in_'json-path-parent_json-path-assert'.html @@ -0,0 +1,1144 @@ + + + + + Test Results — Tests in 'json-path-parent.json-path-assert' + + + + + + + + + +
+ +
+ +
+
+ + + 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 01c7db03..6dca7db2 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java +++ b/json-path/src/main/java/com/jayway/jsonpath/JsonPath.java @@ -16,6 +16,7 @@ package com.jayway.jsonpath; import com.jayway.jsonpath.internal.*; +import com.jayway.jsonpath.internal.PathEvaluator; import com.jayway.jsonpath.internal.path.PathCompiler; import com.jayway.jsonpath.spi.json.JsonProvider; @@ -139,6 +140,23 @@ public class JsonPath { return path.isDefinite(); } + +// public boolean isFunctionPath() { +// return path.isFunctionPath(); +// } +// +// public boolean isRootPath() { +// return path.isRootPath(); +// } + + public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration) { + return evaluate(document, rootDocument, configuration, false); + } + + public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration, boolean forUpdate) { + EvaluationContext evaluationContext = null; + return resultByConfiguration(document, configuration, evaluationContext); + } /** * Applies this JsonPath to the provided json document. * Note that the document must be identified as either a List or Map by @@ -165,46 +183,8 @@ public class JsonPath { */ @SuppressWarnings("unchecked") public T read(Object jsonObject, Configuration configuration) { - boolean optAsPathList = configuration.containsOption(AS_PATH_LIST); - boolean optAlwaysReturnList = configuration.containsOption(Option.ALWAYS_RETURN_LIST); - boolean optSuppressExceptions = configuration.containsOption(Option.SUPPRESS_EXCEPTIONS); - - if (path.isFunctionPath()) { - if (optAsPathList || optAlwaysReturnList) { - if (optSuppressExceptions) { - return (T) (path.isDefinite() ? null : configuration.jsonProvider().createArray()); - } - throw new JsonPathException("Options " + AS_PATH_LIST + " and " + ALWAYS_RETURN_LIST + " are not allowed when using path functions!"); - } - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration); - if (optSuppressExceptions && evaluationContext.getPathList().isEmpty()) { - return (T) (path.isDefinite() ? null : configuration.jsonProvider().createArray()); - } - return evaluationContext.getValue(true); - } else if (optAsPathList) { - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration); - if (optSuppressExceptions && evaluationContext.getPathList().isEmpty()) { - return (T) configuration.jsonProvider().createArray(); - } - return (T) evaluationContext.getPath(); - } else { - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration); - if (optSuppressExceptions && evaluationContext.getPathList().isEmpty()) { - if (optAlwaysReturnList) { - return (T) configuration.jsonProvider().createArray(); - } else { - return (T) (path.isDefinite() ? null : configuration.jsonProvider().createArray()); - } - } - Object res = evaluationContext.getValue(false); - if (optAlwaysReturnList && path.isDefinite()) { - Object array = configuration.jsonProvider().createArray(); - configuration.jsonProvider().setArrayIndex(array, 0, res); - return (T) array; - } else { - return (T) res; - } - } + PathEvaluator evaluator = new PathEvaluator(path, configuration); + return evaluator.evaluate(jsonObject); } /** @@ -218,7 +198,7 @@ public class JsonPath { public T set(Object jsonObject, Object newVal, Configuration configuration) { notNull(jsonObject, "json can not be null"); notNull(configuration, "configuration can not be null"); - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true); + EvaluationContext evaluationContext = evaluate(jsonObject, jsonObject, configuration, true); if (evaluationContext.getPathList().isEmpty()) { boolean optSuppressExceptions = configuration.containsOption(Option.SUPPRESS_EXCEPTIONS); if (optSuppressExceptions) { @@ -246,7 +226,7 @@ public class JsonPath { notNull(jsonObject, "json can not be null"); notNull(configuration, "configuration can not be null"); notNull(mapFunction, "mapFunction can not be null"); - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true); + EvaluationContext evaluationContext = evaluate(jsonObject, jsonObject, configuration, true); if (evaluationContext.getPathList().isEmpty()) { boolean optSuppressExceptions = configuration.containsOption(Option.SUPPRESS_EXCEPTIONS); if (optSuppressExceptions) { @@ -273,7 +253,7 @@ public class JsonPath { public T delete(Object jsonObject, Configuration configuration) { notNull(jsonObject, "json can not be null"); notNull(configuration, "configuration can not be null"); - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true); + EvaluationContext evaluationContext = evaluate(jsonObject, jsonObject, configuration, true); if (evaluationContext.getPathList().isEmpty()) { boolean optSuppressExceptions = configuration.containsOption(Option.SUPPRESS_EXCEPTIONS); if (optSuppressExceptions) { @@ -300,7 +280,7 @@ public class JsonPath { public T add(Object jsonObject, Object value, Configuration configuration) { notNull(jsonObject, "json can not be null"); notNull(configuration, "configuration can not be null"); - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true); + EvaluationContext evaluationContext = evaluate(jsonObject, jsonObject, configuration, true); if (evaluationContext.getPathList().isEmpty()) { boolean optSuppressExceptions = configuration.containsOption(Option.SUPPRESS_EXCEPTIONS); if (optSuppressExceptions) { @@ -329,7 +309,7 @@ public class JsonPath { notNull(jsonObject, "json can not be null"); notEmpty(key, "key can not be null or empty"); notNull(configuration, "configuration can not be null"); - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true); + EvaluationContext evaluationContext = evaluate(jsonObject, jsonObject, configuration, true); if (evaluationContext.getPathList().isEmpty()) { boolean optSuppressExceptions = configuration.containsOption(Option.SUPPRESS_EXCEPTIONS); if (optSuppressExceptions) { @@ -348,7 +328,7 @@ public class JsonPath { notNull(jsonObject, "json can not be null"); notEmpty(newKeyName, "newKeyName can not be null or empty"); notNull(configuration, "configuration can not be null"); - EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration, true); + EvaluationContext evaluationContext = evaluate(jsonObject, jsonObject, configuration, true); for (PathRef updateOperation : evaluationContext.updateOperations()) { boolean optSuppressExceptions = configuration.containsOption(Option.SUPPRESS_EXCEPTIONS); try { @@ -554,17 +534,17 @@ public class JsonPath { /** * Creates a new JsonPath and applies it to the provided Json object * - * @param jsonURL url pointing to json doc + // * @param jsonURL url pointing to json doc * @param jsonPath the json path * @param filters filters to be applied to the filter place holders [?] in the path * @param expected return type * @return list of objects matched by the given path */ - @SuppressWarnings({"unchecked"}) +// @SuppressWarnings({"unchecked"}) @Deprecated - public static T read(URL jsonURL, String jsonPath, Predicate... filters) throws IOException { - return new ParseContextImpl().parse(jsonURL).read(jsonPath, filters); - } +// public static T read(URL jsonURL, String jsonPath, Predicate... filters) throws IOException { +// return new ParseContextImpl().parse(jsonURL).read(jsonPath, filters); +// } /** * Creates a new JsonPath and applies it to the provided Json object diff --git a/json-path/src/main/java/com/jayway/jsonpath/PathEvaluator.java b/json-path/src/main/java/com/jayway/jsonpath/PathEvaluator.java new file mode 100644 index 00000000..33fa3366 --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/PathEvaluator.java @@ -0,0 +1,35 @@ +package com.jayway.jsonpath.internal; + +import com.jayway.jsonpath.Configuration; +import static com.jayway.jsonpath.internal.Utils.*; +import static com.jayway.jsonpath.Option.AS_PATH_LIST; + +public class PathEvaluator { + + private final Path path; + private final Configuration configuration; + + public PathEvaluator(Path path, Configuration configuration) { + notNull(path, "path can not be null"); + notNull(configuration, "configuration can not be null"); + this.path = path; + this.configuration = configuration; + } + + public T evaluate(Object jsonObject) { + boolean optAsPathList = configuration.containsOption(AS_PATH_LIST); + EvaluationContext evaluationContext = path.evaluate(jsonObject, jsonObject, configuration); + + + return resultByConfiguration(jsonObject, evaluationContext); + } + + private T resultByConfiguration(Object jsonObject, EvaluationContext evaluationContext) { + if(configuration.containsOption(AS_PATH_LIST)){ + return (T)evaluationContext.getPathList(); + } else { + return (T) jsonObject; + } + } + +} \ No newline at end of file diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java index 322a1719..8afba610 100755 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java @@ -375,27 +375,28 @@ public class EvaluatorFactory { private static class NoneOfEvaluator implements Evaluator { @Override public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) { - ValueListNode rightValueListNode; - if (right.isJsonNode()) { - ValueNode vn = right.asJsonNode().asValueListNode(ctx); + ValueListNode rightValueListNode = extractValueListNode(right, ctx); + ValueListNode leftValueListNode = extractValueListNode(left, ctx); + + return areAllElementsDifferent(leftValueListNode, rightValueListNode); + } + + private ValueListNode extractValueListNode(ValueNode node, Predicate.PredicateContext ctx) { + if (node.isJsonNode()) { + ValueNode vn = node.asJsonNode().asValueListNode(ctx); if (vn.isUndefinedNode()) { - return false; + return null; // or handle undefined case accordingly } else { - rightValueListNode = vn.asValueListNode(); + return vn.asValueListNode(); } } else { - rightValueListNode = right.asValueListNode(); + return node.asValueListNode(); } - ValueListNode leftValueListNode; - if (left.isJsonNode()) { - ValueNode vn = left.asJsonNode().asValueListNode(ctx); - if (vn.isUndefinedNode()) { - return false; - } else { - leftValueListNode = vn.asValueListNode(); - } - } else { - leftValueListNode = left.asValueListNode(); + } + + private boolean areAllElementsDifferent(ValueListNode leftValueListNode, ValueListNode rightValueListNode) { + if (leftValueListNode == null || rightValueListNode == null) { + return false; // or handle the case where one of the lists is null } for (ValueNode leftValueNode : leftValueListNode) { @@ -405,7 +406,9 @@ public class EvaluatorFactory { } } } + return true; } + } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java index cdf0dd97..b9b6529f 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java @@ -135,26 +135,44 @@ public abstract class ValueNode { } private static boolean isJson(Object o) { - if(o == null || !(o instanceof String)){ + if (o == null || !(o instanceof String)) { return false; } + String str = o.toString().trim(); + if (str.length() <= 1) { return false; } + char c0 = str.charAt(0); char c1 = str.charAt(str.length() - 1); - if ((c0 == '[' && c1 == ']') || (c0 == '{' && c1 == '}')){ - try { - new JSONParser(JSONParser.MODE_PERMISSIVE).parse(str); - return true; - } catch(Exception e){ - return false; - } + + if (isJsonArray(c0, c1) || isJsonObject(c0, c1)) { + return isValidJson(str); } + return false; } + private static boolean isJsonArray(char c0, char c1) { + return c0 == '[' && c1 == ']'; + } + + private static boolean isJsonObject(char c0, char c1) { + return c0 == '{' && c1 == '}'; + } + + private static boolean isValidJson(String str) { + try { + new JSONParser(JSONParser.MODE_PERMISSIVE).parse(str); + return true; + } catch (Exception e) { + return false; + } + } + + //---------------------------------------------------- diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/PassthruPathFunction.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/PassthruPathFunction.java index 36d7da77..0be65205 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/PassthruPathFunction.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/PassthruPathFunction.java @@ -13,7 +13,7 @@ import java.util.List; public class PassthruPathFunction implements PathFunction { @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + public Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { return model; } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunction.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunction.java index ac3a353b..6e0e98b4 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunction.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/PathFunction.java @@ -32,5 +32,5 @@ public interface PathFunction { * @param parameters * @return result */ - Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters); + Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/Append.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/Append.java index ed39d4a8..aa2bbbdc 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/Append.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/Append.java @@ -16,7 +16,7 @@ import java.util.List; */ public class Append implements PathFunction { @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + public Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { JsonProvider jsonProvider = ctx.configuration().jsonProvider(); if (parameters != null && parameters.size() > 0) { for (Parameter param : parameters) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/KeySetFunction.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/KeySetFunction.java index 049d6de0..847e6a95 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/KeySetFunction.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/json/KeySetFunction.java @@ -14,7 +14,7 @@ import java.util.List; public class KeySetFunction implements PathFunction { @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + public Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { if (ctx.configuration().jsonProvider().isMap(model)) { return ctx.configuration().jsonProvider().getPropertyKeys(model); } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/AbstractAggregation.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/AbstractAggregation.java index cbc9f7bc..3d74cd29 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/AbstractAggregation.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/AbstractAggregation.java @@ -23,7 +23,7 @@ public abstract class AbstractAggregation implements PathFunction { * @param value * The numerical value to process next */ - protected abstract void next(Number value); + protected abstract void processNumericValue(Number value); /** * Obtains the value generated via the series of next value calls @@ -31,31 +31,37 @@ public abstract class AbstractAggregation implements PathFunction { * @return * A numerical answer based on the input value provided */ - protected abstract Number getValue(); + protected abstract Number getAggregatedValue(); @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + public Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { int count = 0; - if(ctx.configuration().jsonProvider().isArray(model)){ - Iterable objects = ctx.configuration().jsonProvider().toIterable(model); - for (Object obj : objects) { - if (obj instanceof Number) { - Number value = (Number) obj; + if (ctx.configuration().jsonProvider().isArray(model)) { + Iterable arrayElements = ctx.configuration().jsonProvider().toIterable(model); + + for (Object arrayElement : arrayElements) { + if (arrayElement instanceof Number) { + Number numericValue = (Number) arrayElement; count++; - next(value); + processNumericValue(numericValue); } } } + if (parameters != null) { - for (Number value : Parameter.toList(Number.class, ctx, parameters)) { + for (Number parameterValue : Parameter.toList(Number.class, ctx, parameters)) { count++; - next(value); + processNumericValue(parameterValue); } } + if (count != 0) { - return getValue(); + return getAggregatedValue(); } + throw new JsonPathException("Aggregation function attempted to calculate value using empty array"); } + + } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Average.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Average.java index f4c6788e..83959975 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Average.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Average.java @@ -11,13 +11,13 @@ public class Average extends AbstractAggregation { private Double count = 0d; @Override - protected void next(Number value) { + protected void processNumericValue(Number value) { count++; summation += value.doubleValue(); } @Override - protected Number getValue() { + protected Number getAggregatedValue() { if (count != 0d) { return summation / count; } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Max.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Max.java index 27570bf6..35298722 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Max.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Max.java @@ -9,14 +9,14 @@ public class Max extends AbstractAggregation { private Double max = Double.MIN_VALUE; @Override - protected void next(Number value) { + protected void processNumericValue(Number value) { if (max < value.doubleValue()) { max = value.doubleValue(); } } @Override - protected Number getValue() { + protected Number getAggregatedValue() { return max; } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Min.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Min.java index 3c57e5f2..125f9849 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Min.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Min.java @@ -9,14 +9,14 @@ public class Min extends AbstractAggregation { private Double min = Double.MAX_VALUE; @Override - protected void next(Number value) { + protected void processNumericValue(Number value) { if (min > value.doubleValue()) { min = value.doubleValue(); } } @Override - protected Number getValue() { + protected Number getAggregatedValue() { return min; } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/StandardDeviation.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/StandardDeviation.java index 0a83d8a8..799d4f7d 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/StandardDeviation.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/StandardDeviation.java @@ -11,14 +11,14 @@ public class StandardDeviation extends AbstractAggregation { private Double count = 0d; @Override - protected void next(Number value) { + protected void processNumericValue(Number value) { sum += value.doubleValue(); sumSq += value.doubleValue() * value.doubleValue(); count++; } @Override - protected Number getValue() { + protected Number getAggregatedValue() { return Math.sqrt(sumSq/count - sum*sum/count/count); } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Sum.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Sum.java index 3996bb43..8a7002e6 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Sum.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/numeric/Sum.java @@ -9,12 +9,12 @@ public class Sum extends AbstractAggregation { private Double summation = 0d; @Override - protected void next(Number value) { + protected void processNumericValue(Number value) { summation += value.doubleValue(); } @Override - protected Number getValue() { + protected Number getAggregatedValue() { return summation; } } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/sequence/AbstractSequenceAggregation.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/sequence/AbstractSequenceAggregation.java index 24c87e13..dd5b8153 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/sequence/AbstractSequenceAggregation.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/sequence/AbstractSequenceAggregation.java @@ -19,7 +19,7 @@ public abstract class AbstractSequenceAggregation implements PathFunction { protected abstract int targetIndex(EvaluationContext ctx, List parameters); @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + public Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { if(ctx.configuration().jsonProvider().isArray(model)){ Iterable objects = ctx.configuration().jsonProvider().toIterable(model); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Concatenate.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Concatenate.java index d499afef..725805cd 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Concatenate.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Concatenate.java @@ -14,7 +14,7 @@ import java.util.List; */ public class Concatenate implements PathFunction { @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + public Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { StringBuilder result = new StringBuilder(); if(ctx.configuration().jsonProvider().isArray(model)){ Iterable objects = ctx.configuration().jsonProvider().toIterable(model); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java b/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java index ea8ab1ff..b0c8d2fc 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Length.java @@ -40,7 +40,7 @@ public class Length implements PathFunction { * @return */ @Override - public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { + public Object aggregateAndInvoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List parameters) { if (null != parameters && parameters.size() > 0) { // Set the tail of the first parameter, when its not a function path parameter (which wouldn't make sense diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java index 0f449895..85c95f57 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/FunctionPathToken.java @@ -38,7 +38,7 @@ public class FunctionPathToken extends PathToken { public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) { PathFunction pathFunction = PathFunctionFactory.newFunction(functionName); evaluateParameters(currentPath, parent, model, ctx); - Object result = pathFunction.invoke(currentPath, parent, model, ctx, functionParams); + Object result = pathFunction.aggregateAndInvoke(currentPath, parent, model, ctx, functionParams); ctx.addResult(currentPath + "." + functionName, parent, result); cleanWildcardPathToken(); if (!isLeaf()) { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java index 34cf1402..b1eb7e66 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java @@ -215,7 +215,7 @@ public abstract class PathToken { } public void invoke(PathFunction pathFunction, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) { - ctx.addResult(currentPath, parent, pathFunction.invoke(currentPath, parent, model, ctx, null)); + ctx.addResult(currentPath, parent, pathFunction.aggregateAndInvoke(currentPath, parent, model, ctx, null)); } public abstract void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx); 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 ae165927..9a54dcbb 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 @@ -212,18 +212,42 @@ public class JacksonJsonNodeJsonProvider extends AbstractJsonProvider { @Override public int length(Object obj) { + JsonLengthCalculator lengthCalculator = getLengthCalculator(obj); + return lengthCalculator.calculateLength(obj); + } + + private JsonLengthCalculator getLengthCalculator(Object obj) { if (isArray(obj)) { - return toJsonArray(obj).size(); + return new JsonArrayLengthCalculator(); } else if (isMap(obj)) { - return toJsonObject(obj).size(); + return new JsonObjectLengthCalculator(); } else { + return new TextNodeLengthCalculator(); + } + } + + public class JsonArrayLengthCalculator implements JsonLengthCalculator { + @Override + public int calculateLength(Object obj) { + return toJsonArray(obj).size(); + } + } + public class JsonObjectLengthCalculator implements JsonLengthCalculator { + @Override + public int calculateLength(Object obj) { + return toJsonObject(obj).size(); + } + } + + public class TextNodeLengthCalculator implements JsonLengthCalculator { + @Override + public int calculateLength(Object obj) { if (obj instanceof TextNode) { TextNode element = (TextNode) obj; return element.size(); } + throw new JsonPathException("length operation cannot be applied to " + (obj != null ? obj.getClass().getName() : "null")); } - throw new JsonPathException("length operation can not applied to " + (obj != null ? obj.getClass().getName() - : "null")); } @Override diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonLengthCalculator.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonLengthCalculator.java new file mode 100644 index 00000000..1056cdb0 --- /dev/null +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonLengthCalculator.java @@ -0,0 +1,5 @@ +package com.jayway.jsonpath.spi.json; + +public interface JsonLengthCalculator { + int calculateLength(Object obj); +} diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/JettisonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/JettisonProviderTest.java new file mode 100644 index 00000000..266877cc --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/JettisonProviderTest.java @@ -0,0 +1,34 @@ +//package com.jayway.jsonpath.internal; +// +//import com.jayway.jsonpath.spi.json.JettisonProvider; +//import org.junit.Before; +//import org.junit.Test; +// +//import static org.junit.Assert.assertEquals; +//import static org.junit.Assert.assertTrue; +// +//public class JettisonProviderTest { +// +// private JettisonProvider jsonProvider; +// +// @Before +// public void setUp() { +// jsonProvider = new JettisonProvider(); +// } +// +// @Test +// public void parseValidJsonString() { +// //Input json +// String jsonString = "{\"name\":\"Vishesh\",\"age\":21}"; +// +// // When parsing a valid JSON string +// Object result = jsonProvider.parse(jsonString); +// +// assertTrue(jsonProvider.isMap(result)); +// +// // expected values +// assertEquals("Vishesh", jsonProvider.getMapValue(result, "name")); +// assertEquals(21, jsonProvider.getMapValue(result, "age")); +// } +// +//} diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/JsonOrgJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonOrgJsonProviderTest.java new file mode 100644 index 00000000..d6558328 --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/JsonOrgJsonProviderTest.java @@ -0,0 +1,46 @@ +//package com.jayway.jsonpath.internal; +// +//import com.jayway.jsonpath.spi.json.JsonOrgJsonProvider; +//import org.junit.Before; +//import org.junit.Test; +// +//import java.io.ByteArrayInputStream; +//import java.io.InputStream; +//import java.nio.charset.StandardCharsets; +// +//import static org.junit.Assert.assertEquals; +//import static org.junit.Assert.assertTrue; +// +//public class JsonOrgJsonProviderTest { +// private JsonOrgJsonProvider jsonProvider; +// @Before +// public void setUp() { +// jsonProvider = new JsonOrgJsonProvider(); +// } +// @Test +// public void parseValidJsonString() { +// //input json +// String jsonString = "{\"name\":\"Raj\",\"age\":31}"; +// +// // When parsing a valid JSON string +// Object result = jsonProvider.parse(jsonString); +// +// assertTrue(jsonProvider.isMap(result)); +// assertEquals("Raj", jsonProvider.getMapValue(result, "name")); +// assertEquals(31, jsonProvider.getMapValue(result, "age")); +// } +// @Test +// public void parseValidJsonInputStream() { +// +// String jsonString = "{\"name\":\"Raj\",\"age\":31}"; +// InputStream jsonStream = new ByteArrayInputStream(jsonString.getBytes(StandardCharsets.UTF_8)); +// +// // When parsing valid JSON from an InputStream +// Object result = jsonProvider.parse(jsonStream, StandardCharsets.UTF_8.name()); +// +// assertTrue(jsonProvider.isMap(result)); +// // expected values +// assertEquals("Raj", jsonProvider.getMapValue(result, "name")); +// assertEquals(31, jsonProvider.getMapValue(result, "age")); +// } +//} diff --git a/json-path/src/test/java/com/jayway/jsonpath/internal/TapestryMappingProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/internal/TapestryMappingProviderTest.java new file mode 100644 index 00000000..725b5577 --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/internal/TapestryMappingProviderTest.java @@ -0,0 +1,42 @@ +//package com.jayway.jsonpath.internal; +// +//import com.jayway.jsonpath.Configuration; +//import com.jayway.jsonpath.TypeRef; +//import com.jayway.jsonpath.spi.mapper.TapestryMappingProvider; +//import org.junit.Before; +//import org.junit.Test; +// +//import java.util.List; +// +//import static org.junit.Assert.assertNull; +//import static org.junit.Assert.fail; +// +//public class TapestryMappingProviderTest { +// private TapestryMappingProvider mappingProvider; +// private Configuration configuration; +// @Before +// public void setUp() { +// mappingProvider = new TapestryMappingProvider(); +// configuration = Configuration.defaultConfiguration(); +// } +// @Test +// public void mapNullSourceToNullTarget() { +// Object source = null; +// +// Object result = mappingProvider.map(source, List.class, configuration); +// +// //result should be null +// assertNull(result); +// } +// @Test +// public void mapArrayToJsonRef() { +// String[] source = new String[]{"Red", "Green", "Blue"}; +// +// try { +// Object result = mappingProvider.map(source, new TypeRef>() {}, configuration); +// fail("Expected UnsupportedOperationException"); +// } catch (UnsupportedOperationException e) { +// // UnsupportedOperationException should be thrown +// } +// } +//}