From 38c7e791f6b95d4a9d62032444d23aaea37a28d6 Mon Sep 17 00:00:00 2001 From: Ari Fogel Date: Wed, 30 Nov 2016 11:56:24 -0800 Subject: [PATCH 01/25] implement not (!) operator in filter expressions --- .../jsonpath/internal/filter/FilterCompiler.java | 15 ++++++++++++++- .../internal/filter/LogicalExpressionNode.java | 10 +++++++++- .../jsonpath/internal/filter/LogicalOperator.java | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index 7126b278..e5eb39a3 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -120,7 +120,7 @@ public class FilterCompiler { /* * LogicalOR = LogicalAND { '||' LogicalAND } * LogicalAND = LogicalANDOperand { '&&' LogicalANDOperand } - * LogicalANDOperand = RelationalExpression | '(' LogicalOR ')' + * LogicalANDOperand = RelationalExpression | '(' LogicalOR ')' | '!' LogicalANDOperand * RelationalExpression = Value [ RelationalOperator Value ] */ @@ -164,6 +164,19 @@ public class FilterCompiler { } private ExpressionNode readLogicalANDOperand() { + int savepoint = filter.skipBlanks().position(); + if (filter.skipBlanks().currentCharIs(NOT)) { + filter.readSignificantChar(NOT); + switch (filter.skipBlanks().currentChar()) { + case DOC_CONTEXT: + case EVAL_CONTEXT: + filter.setPosition(savepoint); + break; + default: + final ExpressionNode op = readLogicalANDOperand(); + return LogicalExpressionNode.createLogicalNot(op); + } + } if (filter.skipBlanks().currentCharIs(OPEN_PARENTHESIS)) { filter.readSignificantChar(OPEN_PARENTHESIS); final ExpressionNode op = readLogicalOR(); diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java index 3a5d9605..57cb3884 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java @@ -10,6 +10,10 @@ public class LogicalExpressionNode extends ExpressionNode { protected List chain = new ArrayList(); private final LogicalOperator operator; + public static ExpressionNode createLogicalNot(ExpressionNode op) { + return new LogicalExpressionNode(op, LogicalOperator.NOT, null); + } + public static LogicalExpressionNode createLogicalOr(ExpressionNode left,ExpressionNode right){ return new LogicalExpressionNode(left, LogicalOperator.OR, right); } @@ -68,13 +72,17 @@ public class LogicalExpressionNode extends ExpressionNode { } } return false; - } else { + } else if (operator == LogicalOperator.AND) { for (ExpressionNode expression : chain) { if(!expression.apply(ctx)){ return false; } } return true; + } else { + ExpressionNode expression = chain.get(0); + return !expression.apply(ctx); } } + } diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java index 376e2ada..809a8560 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalOperator.java @@ -5,6 +5,7 @@ import com.jayway.jsonpath.InvalidPathException; public enum LogicalOperator { AND("&&"), + NOT("!"), OR("||"); private final String operatorString; @@ -24,6 +25,7 @@ public enum LogicalOperator { public static LogicalOperator fromString(String operatorString){ if(AND.operatorString.equals(operatorString)) return AND; + else if(NOT.operatorString.equals(operatorString)) return NOT; else if(OR.operatorString.equals(operatorString)) return OR; else throw new InvalidPathException("Failed to parse operator " + operatorString); } From ec3a79eb77a8e260bda032d909e24b532a0d8390 Mon Sep 17 00:00:00 2001 From: Ari Fogel Date: Wed, 30 Nov 2016 12:01:34 -0800 Subject: [PATCH 02/25] updated documentation for ! filter predicate --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 50e248ca..2d5fad99 100644 --- a/README.md +++ b/README.md @@ -256,6 +256,8 @@ List> books = JsonPath.parse(json) You can use `&&` and `||` to combine multiple predicates `[?(@.price < 10 && @.category == 'fiction')]` , `[?(@.category == 'reference' || @.price > 10)]`. +You can use `!` to negate a predicate `[?(!(@.price < 10 && @.category == 'fiction'))]`. + ###Filter Predicates Predicates can be built using the Filter API as shown below: From 291eabafda585ff95faeb647f146a3b803fb5af7 Mon Sep 17 00:00:00 2001 From: Benjamin Rogge Date: Sun, 12 Feb 2017 17:41:19 -0800 Subject: [PATCH 03/25] enable bigdecimal and -integer for GSONProvider --- .../jsonpath/spi/json/GsonJsonProvider.java | 48 +++++++++------ .../jayway/jsonpath/GsonJsonProviderTest.java | 61 +++++++++++++++++++ 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java index 7a2636a8..0828b295 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/GsonJsonProvider.java @@ -14,28 +14,25 @@ */ package com.jayway.jsonpath.spi.json; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; - -import java.math.BigDecimal; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; - import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; -import com.google.gson.internal.LazilyParsedNumber; - import com.jayway.jsonpath.InvalidJsonException; import com.jayway.jsonpath.JsonPathException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + public class GsonJsonProvider extends AbstractJsonProvider { private static final JsonParser PARSER = new JsonParser(); @@ -86,25 +83,38 @@ public class GsonJsonProvider extends AbstractJsonProvider { return o; } + private static boolean isPrimitiveNumber(final Number n) { + return n instanceof Integer || + n instanceof Double || + n instanceof Long || + n instanceof BigDecimal || + n instanceof BigInteger; + } + private static Number unwrapNumber(final Number n) { Number unwrapped; - if (n instanceof LazilyParsedNumber) { - LazilyParsedNumber lpn = (LazilyParsedNumber) n; - BigDecimal bigDecimal = new BigDecimal(lpn.toString()); + if (!isPrimitiveNumber(n)) { + BigDecimal bigDecimal = new BigDecimal(n.toString()); if (bigDecimal.scale() <= 0) { if (bigDecimal.compareTo(new BigDecimal(Integer.MAX_VALUE)) <= 0) { unwrapped = bigDecimal.intValue(); - } else { + } else if (bigDecimal.compareTo(new BigDecimal(Long.MAX_VALUE)) <= 0){ unwrapped = bigDecimal.longValue(); + } else { + unwrapped = bigDecimal; } } else { - unwrapped = bigDecimal.doubleValue(); + final double doubleValue = bigDecimal.doubleValue(); + if (BigDecimal.valueOf(doubleValue).compareTo(bigDecimal) != 0) { + unwrapped = bigDecimal; + } else { + unwrapped = doubleValue; + } } } else { unwrapped = n; } - return unwrapped; } diff --git a/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java index 8f3ec333..1fc85bd9 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/GsonJsonProviderTest.java @@ -7,6 +7,8 @@ import com.jayway.jsonpath.spi.mapper.MappingException; import org.junit.Test; import java.io.IOException; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.List; import static com.jayway.jsonpath.JsonPath.using; @@ -69,6 +71,65 @@ public class GsonJsonProviderTest extends BaseTest { assertThat(val).isEqualTo(node.getAsLong()); } + @Test + public void doubles_are_unwrapped() { + final String json = "{double-property = 56.78}"; + + JsonElement node = using(GSON_CONFIGURATION).parse(json).read("$.double-property"); + Double val = using(GSON_CONFIGURATION).parse(json).read("$.double-property", Double.class); + + assertThat(val).isEqualTo(56.78); + assertThat(val).isEqualTo(node.getAsDouble()); + } + + @Test + public void bigdecimals_are_unwrapped() { + final BigDecimal bd = BigDecimal.valueOf(Long.MAX_VALUE).add(BigDecimal.valueOf(10.5)); + final String json = "{bd-property = " + bd.toString() + "}"; + + JsonElement node = using(GSON_CONFIGURATION).parse(json).read("$.bd-property"); + BigDecimal val = using(GSON_CONFIGURATION).parse(json).read("$.bd-property", BigDecimal.class); + + assertThat(val).isEqualTo(bd); + assertThat(val).isEqualTo(node.getAsBigDecimal()); + } + + @Test + public void small_bigdecimals_are_unwrapped() { + final BigDecimal bd = BigDecimal.valueOf(10.5); + final String json = "{bd-property = " + bd.toString() + "}"; + + JsonElement node = using(GSON_CONFIGURATION).parse(json).read("$.bd-property"); + BigDecimal val = using(GSON_CONFIGURATION).parse(json).read("$.bd-property", BigDecimal.class); + + assertThat(val).isEqualTo(bd); + assertThat(val).isEqualTo(node.getAsBigDecimal()); + } + + @Test + public void bigintegers_are_unwrapped() { + final BigInteger bi = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.TEN); + final String json = "{bi-property = " + bi.toString() + "}"; + + JsonElement node = using(GSON_CONFIGURATION).parse(json).read("$.bi-property"); + BigInteger val = using(GSON_CONFIGURATION).parse(json).read("$.bi-property", BigInteger.class); + + assertThat(val).isEqualTo(bi); + assertThat(val).isEqualTo(node.getAsBigInteger()); + } + + @Test + public void small_bigintegers_are_unwrapped() { + final BigInteger bi = BigInteger.valueOf(Long.MAX_VALUE); + final String json = "{bi-property = " + bi.toString() + "}"; + + JsonElement node = using(GSON_CONFIGURATION).parse(json).read("$.bi-property"); + BigInteger val = using(GSON_CONFIGURATION).parse(json).read("$.bi-property", BigInteger.class); + + assertThat(val).isEqualTo(bi); + assertThat(val).isEqualTo(node.getAsBigInteger()); + } + @Test public void int_to_long_mapping() { assertThat(using(GSON_CONFIGURATION).parse("{\"val\": 1}").read("val", Long.class)).isEqualTo(1L); From 788223760ac39a5f63e09fca5c6b7ee16923f66c Mon Sep 17 00:00:00 2001 From: Andrew Prentice Date: Tue, 7 Mar 2017 09:41:56 -0500 Subject: [PATCH 04/25] Fixing java.lang.NoClassDefFoundError: com/google/gson/JsonObject when using JsonOrgJsonProvider --- .../com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java index a5b77e88..6760f869 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java @@ -1,6 +1,6 @@ package com.jayway.jsonpath.spi.json; -import com.google.gson.JsonObject; +import org.json.JSONObject; import com.jayway.jsonpath.InvalidJsonException; import com.jayway.jsonpath.JsonPathException; import org.json.JSONArray; @@ -62,7 +62,7 @@ public class JsonOrgJsonProvider extends AbstractJsonProvider { @Override public Object createMap() { - return new JsonObject(); + return new JSONObject(); } @Override From d3dfaff1b0ca256a1e00f6fffdec6e8fde865f6e Mon Sep 17 00:00:00 2001 From: jochenberger Date: Fri, 17 Mar 2017 10:07:24 +0100 Subject: [PATCH 05/25] Exclude transitive ASM dependency We don't need the bean mapping features and it causes issues Fixes #228, #224, #213 --- json-path/build.gradle | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/json-path/build.gradle b/json-path/build.gradle index fa79910b..bb099540 100644 --- a/json-path/build.gradle +++ b/json-path/build.gradle @@ -14,7 +14,10 @@ jar { } dependencies { - compile libs.jsonSmart + compile (libs.jsonSmart){ + // see https://github.com/jayway/JsonPath/issues/228, https://github.com/netplex/json-smart-v2/issues/20 + exclude group: 'org.ow2.asm', module: 'asm' + } compile libs.slf4jApi compile libs.jacksonDatabind, optional compile libs.gson, optional From eefd9b8b75d513900929e168f0bac692de5edef0 Mon Sep 17 00:00:00 2001 From: jochenberger Date: Fri, 17 Mar 2017 10:19:41 +0100 Subject: [PATCH 06/25] upgrade tapestry-json --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 623cba9f..0f98a438 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ ext { gson: 'com.google.code.gson:gson:2.3.1', jettison: 'org.codehaus.jettison:jettison:1.3.7', jsonOrg: 'org.json:json:20140107', - tapestryJson: 'org.apache.tapestry:tapestry-json:5.4.0', + tapestryJson: 'org.apache.tapestry:tapestry-json:5.4.1', hamcrestCore: 'org.hamcrest:hamcrest-core:1.3', hamcrestLibrary: 'org.hamcrest:hamcrest-library:1.3', From 2ccde968c2d573c3d2570cf861ef2725990cd4d1 Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Fri, 17 Mar 2017 10:32:59 +0100 Subject: [PATCH 07/25] upgrade Gradle wrapper --- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 53638 -> 54212 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 68 +++++++++++++---------- gradlew.bat | 12 +--- json-path-assert/build.gradle | 2 - json-path-web-test/build.gradle | 16 +++--- json-path/build.gradle | 3 - 8 files changed, 54 insertions(+), 53 deletions(-) diff --git a/build.gradle b/build.gradle index 623cba9f..6c644839 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,7 @@ subprojects { } task wrapper(type: Wrapper) { - gradleVersion = '2.11' + gradleVersion = '3.4.1' } //Task used by Heroku for staging diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5ccda13e9cb94678ba179b32452cf3d60dc36353..17279fa9b329dbb32190f8378b275bbb8d3c0c49 100644 GIT binary patch delta 25015 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 pjKj&?)ZEI!h10?5iG#V5i)m&?s_NNQ???q` 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 d&E3fzZvP#M?6VC`aiwA2X$$ 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ec299545..10eb72ab 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri Feb 12 10:36:51 CET 2016 +#Fri Mar 17 10:32:10 CET 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.11-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip diff --git a/gradlew b/gradlew index 9d82f789..4453ccea 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,12 +6,30 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 72d362da..e95643d6 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -49,7 +49,6 @@ goto fail @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/json-path-assert/build.gradle b/json-path-assert/build.gradle index 0a47bd0c..f63e70bb 100644 --- a/json-path-assert/build.gradle +++ b/json-path-assert/build.gradle @@ -1,7 +1,5 @@ apply from: "$rootDir/gradle/publishMaven.gradle" -displayName = "JsonPath Assert" - description = "Assertions on Json using JsonPath" jar { diff --git a/json-path-web-test/build.gradle b/json-path-web-test/build.gradle index 7c185eb4..83eb94fc 100644 --- a/json-path-web-test/build.gradle +++ b/json-path-web-test/build.gradle @@ -1,18 +1,18 @@ apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'application' -displayName = "JsonPath Test Bench" - description = "Web app that compares different JsonPath implementations." mainClassName = 'com.jayway.jsonpath.web.boot.Main' -task createBuildInfoFile << { - def buildInfoFile = new File("$buildDir/classes/main/build-info.properties") - Properties props = new Properties() - props.setProperty('version', project.version.toString()) - props.setProperty('timestamp', project.buildTimestamp) - props.store(buildInfoFile.newWriter(), null) +task createBuildInfoFile { + doLast { + def buildInfoFile = new File("$buildDir/classes/main/build-info.properties") + Properties props = new Properties() + props.setProperty('version', project.version.toString()) + props.setProperty('timestamp', project.buildTimestamp) + props.store(buildInfoFile.newWriter(), null) + } } jar { diff --git a/json-path/build.gradle b/json-path/build.gradle index fa79910b..f8851274 100644 --- a/json-path/build.gradle +++ b/json-path/build.gradle @@ -1,8 +1,5 @@ apply from: "$rootDir/gradle/publishMaven.gradle" - -displayName = "Json Path" - description = "Java port of Stefan Goessner JsonPath." jar { From bc1fe3f7a56be6401d12a88b0d7fb5fff944085c Mon Sep 17 00:00:00 2001 From: jochenberger Date: Wed, 22 Mar 2017 15:01:45 +0100 Subject: [PATCH 08/25] Make jettison optional fixes #250 --- json-path/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-path/build.gradle b/json-path/build.gradle index 9f129c90..5d9d3f14 100644 --- a/json-path/build.gradle +++ b/json-path/build.gradle @@ -6,7 +6,7 @@ jar { baseName 'json-path' manifest { attributes 'Implementation-Title': 'json-path', 'Implementation-Version': version - instruction 'Import-Package', 'org.json.*;resolution:=optional', 'com.google.gson.*;resolution:=optional', 'com.fasterxml.jackson.*;resolution:=optional', 'net.minidev.json.*;resolution:=optional', 'org.apache.tapestry5.json.*;resolution:=optional', '*' + instruction 'Import-Package', 'org.json.*;resolution:=optional', 'com.google.gson.*;resolution:=optional', 'com.fasterxml.jackson.*;resolution:=optional', 'net.minidev.json.*;resolution:=optional', 'org.apache.tapestry5.json.*;resolution:=optional', 'org.codehaus.jettison.*;resolution:=optional', '*' } } From 8ad32cc853a77e957c92a8fd88d209313748bf5d Mon Sep 17 00:00:00 2001 From: jochenberger Date: Wed, 22 Mar 2017 15:05:50 +0100 Subject: [PATCH 09/25] Fix distribution bundle --- json-path/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json-path/build.gradle b/json-path/build.gradle index 9f129c90..7178e210 100644 --- a/json-path/build.gradle +++ b/json-path/build.gradle @@ -79,7 +79,7 @@ task distTar(type: Tar, dependsOn: assemble) { } from(project.configurations.compile) { into 'lib' - exclude { it.file.name.contains('gson') || it.file.name.contains('jackson') || it.file.name.contains('json-2') || it.file.name.contains('jettison') } + exclude { it.file.name.contains('gson') || it.file.name.contains('jackson') || it.file.name.contains('json-2') || it.file.name.contains('jettison') || it.file.name.contains('tapestry') } } from(project.configurations.compile) { into 'lib-optional/jackson' @@ -98,7 +98,7 @@ task distTar(type: Tar, dependsOn: assemble) { include { it.file.name.contains('json-2') } } from(project.configurations.compile) { - into 'lib-optional/jsonOrg' + into 'lib-optional/tapestry' include { it.file.name.contains('tapestry') } } } From dabeeba3c2e24a32924a1b89d20b102125b94459 Mon Sep 17 00:00:00 2001 From: jochenberger Date: Wed, 22 Mar 2017 15:08:41 +0100 Subject: [PATCH 10/25] Update build.gradle --- json-path/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/json-path/build.gradle b/json-path/build.gradle index 7178e210..9b8b0db1 100644 --- a/json-path/build.gradle +++ b/json-path/build.gradle @@ -39,7 +39,7 @@ task distZip(type: Zip, dependsOn: assemble) { } from(project.configurations.compile) { into 'lib' - exclude { it.file.name.contains('gson') || it.file.name.contains('jackson') || it.file.name.contains('json-2') || it.file.name.contains('jettison') } + exclude { it.file.name.contains('gson') || it.file.name.contains('jackson') || it.file.name.contains('json-2') || it.file.name.contains('jettison') || it.file.name.contains('tapestry') } } from(project.configurations.compile) { into 'lib-optional/jackson' @@ -58,7 +58,7 @@ task distZip(type: Zip, dependsOn: assemble) { include { it.file.name.contains('json-2') } } from(project.configurations.compile) { - into 'lib-optional/jsonOrg' + into 'lib-optional/tapestry' include { it.file.name.contains('tapestry') } } } From ed783b58060f53b3b3e864fcbe22e84a4cf1e5fe Mon Sep 17 00:00:00 2001 From: jochenberger Date: Wed, 22 Mar 2017 15:32:34 +0100 Subject: [PATCH 11/25] Don't initialize Configuration if we don't need it --- .../java/com/jayway/jsonpath/internal/filter/ValueNode.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 7506358a..98e2d1c4 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 @@ -805,9 +805,9 @@ public abstract class ValueNode { } public ValueNode evaluate(Predicate.PredicateContext ctx) { - Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options(Option.REQUIRE_PROPERTIES).build(); if (isExistsCheck()) { try { + Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options(Option.REQUIRE_PROPERTIES).build(); Object result = path.evaluate(ctx.item(), ctx.root(), c).getValue(false); return result == JsonProvider.UNDEFINED ? ValueNode.FALSE : ValueNode.TRUE; } catch (PathNotFoundException e) { @@ -842,4 +842,4 @@ public abstract class ValueNode { } -} \ No newline at end of file +} From 7e85a142477dc6eccd0de7c7000e050fe3a968d1 Mon Sep 17 00:00:00 2001 From: jochenberger Date: Wed, 22 Mar 2017 15:50:45 +0100 Subject: [PATCH 12/25] Make LimitingEvaluationListener *static* --- .../src/main/java/com/jayway/jsonpath/internal/JsonContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java index 17ce9bce..50b84a08 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/JsonContext.java @@ -289,7 +289,7 @@ public class JsonContext implements ParseContext, DocumentContext { return this; } - private final class LimitingEvaluationListener implements EvaluationListener { + private final static class LimitingEvaluationListener implements EvaluationListener { final int limit; private LimitingEvaluationListener(int limit) { From 3588439e6bc81f3fda7090f6acaf702a19dd1d31 Mon Sep 17 00:00:00 2001 From: jochenberger Date: Wed, 22 Mar 2017 15:51:49 +0100 Subject: [PATCH 13/25] Make inner class static --- .../jayway/jsonpath/internal/path/EvaluationContextImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/EvaluationContextImpl.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/EvaluationContextImpl.java index 3814419e..3fc7e487 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/EvaluationContextImpl.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/EvaluationContextImpl.java @@ -163,7 +163,7 @@ public class EvaluationContextImpl implements EvaluationContext { return res; } - private class FoundResultImpl implements EvaluationListener.FoundResult { + private static class FoundResultImpl implements EvaluationListener.FoundResult { private final int index; private final String path; From 3aae70f7522fa39d17c54f93ddf2a17178127d2f Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Thu, 23 Mar 2017 09:06:05 +0100 Subject: [PATCH 14/25] avoid some costly calls to String#trim() --- .../jsonpath/internal/CharacterIndex.java | 36 ++++++++++++++++--- .../internal/filter/FilterCompiler.java | 18 +++++----- .../jsonpath/internal/path/PathCompiler.java | 22 +++++++----- 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java b/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java index b93811c3..1aa28679 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java @@ -17,14 +17,16 @@ public class CharacterIndex { private final CharSequence charSequence; private int position; + private int endPosition; public CharacterIndex(CharSequence charSequence) { this.charSequence = charSequence; this.position = 0; + this.endPosition = charSequence.length() - 1; } public int length() { - return charSequence.length(); + return endPosition + 1; } public char charAt(int idx) { @@ -39,6 +41,10 @@ public class CharacterIndex { return (charSequence.charAt(position) == c); } + public boolean lastCharIs(char c) { + return charSequence.charAt(endPosition) == c; + } + public boolean nextCharIs(char c) { return inBounds(position + 1) && (charSequence.charAt(position + 1) == c); } @@ -47,12 +53,21 @@ public class CharacterIndex { return setPosition(position + charCount); } + public int decrementEndPosition(int charCount) { + return setEndPosition(endPosition - charCount); + } + public int setPosition(int newPosition) { //position = min(newPosition, charSequence.length() - 1); position = newPosition; return position; } + private int setEndPosition(int newPosition) { + endPosition = newPosition; + return endPosition; + } + public int position(){ return position; } @@ -244,7 +259,7 @@ public class CharacterIndex { } public boolean currentIsTail() { - return position >= charSequence.length()-1; + return position >= endPosition; } public boolean hasMoreCharacters() { @@ -252,7 +267,7 @@ public class CharacterIndex { } public boolean inBounds(int idx) { - return (idx >= 0) && (idx < charSequence.length()); + return (idx >= 0) && (idx <= endPosition); } public boolean inBounds() { return inBounds(position); @@ -281,9 +296,22 @@ public class CharacterIndex { } public CharacterIndex skipBlanks() { - while (inBounds() && currentChar() == SPACE){ + while (inBounds() && position < endPosition && currentChar() == SPACE){ incrementPosition(1); } return this; } + + private CharacterIndex skipBlanksAtEnd() { + while (inBounds() && position < endPosition && lastCharIs(SPACE)){ + decrementEndPosition(1); + } + return this; + } + + public CharacterIndex trim() { + skipBlanks(); + skipBlanksAtEnd(); + return this; + } } \ No newline at end of file diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java index e5eb39a3..67b512e4 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java @@ -54,20 +54,22 @@ public class FilterCompiler { } private FilterCompiler(String filterString) { - filterString = filterString.trim(); - if (!filterString.startsWith("[") || !filterString.endsWith("]")) { + filter = new CharacterIndex(filterString); + filter.trim(); + if (!filter.currentCharIs('[') || !filter.lastCharIs(']')) { throw new InvalidPathException("Filter must start with '[' and end with ']'. " + filterString); } - filterString = filterString.substring(1, filterString.length() - 1).trim(); - if (!filterString.startsWith("?")) { + filter.incrementPosition(1); + filter.decrementEndPosition(1); + filter.trim(); + if (!filter.currentCharIs('?')) { throw new InvalidPathException("Filter must start with '[?' and end with ']'. " + filterString); } - filterString = filterString.substring(1).trim(); - if (!filterString.startsWith("(") || !filterString.endsWith(")")) { + filter.incrementPosition(1); + filter.trim(); + if (!filter.currentCharIs('(') || !filter.lastCharIs(')')) { throw new InvalidPathException("Filter must start with '[?(' and end with ')]'. " + filterString); } - - filter = new CharacterIndex(filterString); } public Predicate compile() { diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java index f83e953a..12e18798 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java @@ -45,9 +45,13 @@ public class PathCompiler { private final LinkedList filterStack; private final CharacterIndex path; - private PathCompiler(String path, LinkedList filterStack) { + private PathCompiler(String path, LinkedList filterStack){ + this(new CharacterIndex(path), filterStack); + } + + private PathCompiler(CharacterIndex path, LinkedList filterStack){ this.filterStack = filterStack; - this.path = new CharacterIndex(path); + this.path = path; } private Path compile() { @@ -57,16 +61,18 @@ public class PathCompiler { public static Path compile(String path, final Predicate... filters) { try { - path = path.trim(); + CharacterIndex ci = new CharacterIndex(path); + ci.trim(); - if(!(path.charAt(0) == DOC_CONTEXT) && !(path.charAt(0) == EVAL_CONTEXT)){ - path = "$." + path; + if(!( ci.charAt(0) == DOC_CONTEXT) && !( ci.charAt(0) == EVAL_CONTEXT)){ + ci = new CharacterIndex("$." + path); + ci.trim(); } - if(path.endsWith(".")){ + if(ci.lastCharIs('.')){ fail("Path must not end with a '.' or '..'"); } - LinkedList filterStack = new LinkedList(asList(filters)); - Path p = new PathCompiler(path.trim(), filterStack).compile(); + LinkedList filterStack = new LinkedList(asList(filters)); + Path p = new PathCompiler(ci, filterStack).compile(); return p; } catch (Exception e) { InvalidPathException ipe; From 01118a7214e21dd7d0cd270a877f7bc2c3a2783f Mon Sep 17 00:00:00 2001 From: jochenberger Date: Thu, 23 Mar 2017 09:15:56 +0100 Subject: [PATCH 15/25] Don't create appender when not needed, remove unused variable declaration --- .../java/com/jayway/jsonpath/internal/path/PathCompiler.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java index 12e18798..36d6b822 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java @@ -109,7 +109,6 @@ public class PathCompiler { } RootPathToken pathToken = PathTokenFactory.createRootPathToken(path.currentChar()); - PathTokenAppender appender = pathToken.getPathTokenAppender(); if (path.currentIsTail()) { return pathToken; @@ -121,6 +120,7 @@ public class PathCompiler { fail("Illegal character at position " + path.position() + " expected '.' or '["); } + PathTokenAppender appender = pathToken.getPathTokenAppender(); readNextToken(appender); return pathToken; @@ -267,7 +267,6 @@ public class PathCompiler { * an array. */ private List parseFunctionParameters(String funcName) { - PathToken currentToken; ParamType type = null; // Parenthesis starts at 1 since we're marking the start of a function call, the close paren will denote the From 43414d845715bdd1054589efa1a7c86b01663efa Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Thu, 23 Mar 2017 11:07:02 +0100 Subject: [PATCH 16/25] support negative array indexes --- .../jsonpath/internal/path/ArrayIndexOperation.java | 2 +- .../com/jayway/jsonpath/internal/path/PathToken.java | 3 ++- .../jsonpath/old/internal/ArrayIndexFilterTest.java | 9 +++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java index 8fde93a9..cbfa0253 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java @@ -42,7 +42,7 @@ public class ArrayIndexOperation { //check valid chars for (int i = 0; i < operation.length(); i++) { char c = operation.charAt(i); - if (!isDigit(c) && c != ',' && c != ' ') { + if (!isDigit(c) && c != ',' && c != ' ' && c != '-') { throw new InvalidPathException("Failed to parse ArrayIndexOperation: " + operation); } } 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 dc22dda1..e4d23604 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 @@ -125,8 +125,9 @@ public abstract class PathToken { protected void handleArrayIndex(int index, String currentPath, Object model, EvaluationContextImpl ctx) { String evalPath = Utils.concat(currentPath, "[", String.valueOf(index), "]"); PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, index) : PathRef.NO_OP; + int effectiveIndex = index < 0 ? ctx.jsonProvider().length(model) + index : index; try { - Object evalHit = ctx.jsonProvider().getArrayIndex(model, index); + Object evalHit = ctx.jsonProvider().getArrayIndex(model, effectiveIndex); if (isLeaf()) { ctx.addResult(evalPath, pathRef, evalHit); } else { diff --git a/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java index 434775af..eaada166 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java @@ -1,6 +1,9 @@ package com.jayway.jsonpath.old.internal; import com.jayway.jsonpath.JsonPath; + +import org.junit.Assert; + import org.hamcrest.Matchers; import org.junit.Test; @@ -43,4 +46,10 @@ public class ArrayIndexFilterTest { assertThat(result, Matchers.contains(1, 3, 5)); } + @Test + public void can_access_items_from_end_with_negative_index() { + int result = JsonPath.parse(JSON).read("$[-3]"); + Assert.assertEquals(8, result); + } + } From da0c048f4efa8fe657820bc77c58aadef4e00a8b Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Thu, 23 Mar 2017 11:07:02 +0100 Subject: [PATCH 17/25] add example for negative array index --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5a7a6c85..e0953842 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Given the json | $.store.* | All things, both books and bicycles | | $.store..price | The price of everything | | $..book[2] | The third book | +| $..book[-2] | The second to last book | | $..book[0,1] | The first two books | | $..book[:2] | All books from index 0 (inclusive) until index 2 (exclusive) | | $..book[1:2] | All books from index 1 (inclusive) until index 2 (exclusive) | From 2774037a5b272b53a33bc13f0466bf1bec215cad Mon Sep 17 00:00:00 2001 From: jochenberger Date: Thu, 23 Mar 2017 14:54:23 +0100 Subject: [PATCH 18/25] Fix JSON detection --- .../java/com/jayway/jsonpath/internal/filter/ValueNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 98e2d1c4..3f3914e4 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 @@ -154,7 +154,7 @@ public abstract class ValueNode { if ((c0 == '[' && c1 == ']') || (c0 == '{' && c1 == '}')){ try { Configuration.defaultConfiguration().jsonProvider().parse(str); - return false; + return true; } catch(Exception e){ return false; } From 7e9cfc90be53d88b48782eb7e63a27ea37e4dcb3 Mon Sep 17 00:00:00 2001 From: jochenberger Date: Thu, 23 Mar 2017 15:18:39 +0100 Subject: [PATCH 19/25] Add test --- .../src/test/java/com/jayway/jsonpath/FilterTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java index 58493a35..a9c02e76 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/FilterTest.java @@ -89,6 +89,13 @@ public class FilterTest extends BaseTest { assertThat(filter(where("string-key").eq(null)).apply(createPredicateContext(json))).isEqualTo(false); } + @Test + public void arr_eq_evals() { + assertThat(filter(where("arr-empty").eq("[]")).apply(createPredicateContext(json))).isEqualTo(true); + assertThat(filter(where("int-arr").eq("[0,1,2,3,4]")).apply(createPredicateContext(json))).isEqualTo(true); + assertThat(filter(where("int-arr").eq("[0,1,2,3]")).apply(createPredicateContext(json))).isEqualTo(false); + assertThat(filter(where("int-arr").eq("[0,1,2,3,4,5]")).apply(createPredicateContext(json))).isEqualTo(false); + } //---------------------------------------------------------------------------- // // NE From b536af9b9a1e75362ba2a9454c0217f9d706743f Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Thu, 23 Mar 2017 16:00:20 +0100 Subject: [PATCH 20/25] fix result if object does not contain key (fixes #270) --- .../com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java | 3 +-- .../java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java | 8 ++++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java index 6760f869..516ce424 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java @@ -96,11 +96,10 @@ public class JsonOrgJsonProvider extends AbstractJsonProvider { public Object getMapValue(Object obj, String key) { try { JSONObject jsonObject = toJsonObject(obj); - Object o = jsonObject.get(key); if (!jsonObject.has(key)) { return UNDEFINED; } else { - return unwrap(o); + return unwrap(jsonObject.get(key)); } } catch (JSONException e) { throw new JsonPathException(e); diff --git a/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java index d24e30d1..59ba665c 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JsonOrgJsonProviderTest.java @@ -44,4 +44,12 @@ public class JsonOrgJsonProviderTest extends BaseTest { assertThat(books.size()).isEqualTo(4); } + + @Test + public void read_books_with_isbn() { + + JSONArray books = using(JSON_ORG_CONFIGURATION).parse(JSON_DOCUMENT).read("$..book[?(@.isbn)]"); + + assertThat(books.length()).isEqualTo(2); + } } From 7fc262724bf469d1ff9f1036dbe47b9fe1dc2652 Mon Sep 17 00:00:00 2001 From: jochenberger Date: Thu, 23 Mar 2017 16:06:10 +0100 Subject: [PATCH 21/25] Better approach --- .../com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java index 516ce424..0c5f169e 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonOrgJsonProvider.java @@ -96,10 +96,11 @@ public class JsonOrgJsonProvider extends AbstractJsonProvider { public Object getMapValue(Object obj, String key) { try { JSONObject jsonObject = toJsonObject(obj); - if (!jsonObject.has(key)) { + Object o = jsonObject.opt(key); + if (o == null) { return UNDEFINED; } else { - return unwrap(jsonObject.get(key)); + return unwrap(o); } } catch (JSONException e) { throw new JsonPathException(e); From 211beac6ceae5fe9c03d814524f130264124a045 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Thu, 23 Mar 2017 18:19:26 +0100 Subject: [PATCH 22/25] Added test for issue 309. --- .../com/jayway/jsonpath/old/IssuesTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) 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 93d3f8b2..04ffa00f 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 @@ -999,4 +999,24 @@ public class IssuesTest extends BaseTest { assertThat(objectNode.get("can delete").isNull()); assertThat(objectNode.get("can't delete").isNull()); } + + @Test + public void issue_309(){ + + String json = "{\n" + + "\"jsonArr\": [\n" + + " {\n" + + " \"name\":\"nOne\"\n" + + " },\n" + + " {\n" + + " \"name\":\"nTwo\"\n" + + " }\n" + + " ]\n" + + "}"; + + DocumentContext doc = JsonPath.parse(json).set("$.jsonArr[1].name", "Jayway"); + + assertThat(doc.read("$.jsonArr[0].name")).isEqualTo("nOne"); + assertThat(doc.read("$.jsonArr[1].name")).isEqualTo("Jayway"); + } } From b4b0fe3ae0759e70ae2fadcb11fa37faca0a9754 Mon Sep 17 00:00:00 2001 From: Jochen Berger Date: Mon, 27 Mar 2017 08:58:33 +0200 Subject: [PATCH 23/25] upgrade json-smart dependency --- build.gradle | 2 +- json-path/build.gradle | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index fffe227a..fec4e271 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ buildscript { ext { libs = [ slf4jApi: 'org.slf4j:slf4j-api:1.7.16', - jsonSmart: 'net.minidev:json-smart:2.2.1', + jsonSmart: 'net.minidev:json-smart:2.3', jacksonDatabind: 'com.fasterxml.jackson.core:jackson-databind:2.6.3', gson: 'com.google.code.gson:gson:2.3.1', jettison: 'org.codehaus.jettison:jettison:1.3.7', diff --git a/json-path/build.gradle b/json-path/build.gradle index c9328e68..3aec3088 100644 --- a/json-path/build.gradle +++ b/json-path/build.gradle @@ -11,10 +11,7 @@ jar { } dependencies { - compile (libs.jsonSmart){ - // see https://github.com/jayway/JsonPath/issues/228, https://github.com/netplex/json-smart-v2/issues/20 - exclude group: 'org.ow2.asm', module: 'asm' - } + compile libs.jsonSmart compile libs.slf4jApi compile libs.jacksonDatabind, optional compile libs.gson, optional From c23501fcd651d0dbfd30760f634278d54b197a69 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Tue, 28 Mar 2017 09:10:29 +0200 Subject: [PATCH 24/25] Added provided tests for issue #275. --- .../com/jayway/jsonpath/ProviderInTest.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 json-path/src/test/java/com/jayway/jsonpath/ProviderInTest.java diff --git a/json-path/src/test/java/com/jayway/jsonpath/ProviderInTest.java b/json-path/src/test/java/com/jayway/jsonpath/ProviderInTest.java new file mode 100644 index 00000000..0508539c --- /dev/null +++ b/json-path/src/test/java/com/jayway/jsonpath/ProviderInTest.java @@ -0,0 +1,128 @@ +package com.jayway.jsonpath; + +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.google.gson.JsonArray; +import com.jayway.jsonpath.spi.json.GsonJsonProvider; +import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider; +import com.jayway.jsonpath.spi.json.JacksonJsonProvider; +import com.jayway.jsonpath.spi.json.JsonOrgJsonProvider; +import com.jayway.jsonpath.spi.json.JsonSmartJsonProvider; +import com.jayway.jsonpath.spi.mapper.GsonMappingProvider; +import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider; +import com.jayway.jsonpath.spi.mapper.JsonOrgMappingProvider; +import com.jayway.jsonpath.spi.mapper.JsonSmartMappingProvider; +import org.assertj.core.util.Lists; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class ProviderInTest { + private final String JSON = "[{\"foo\": \"bar\"}, {\"foo\": \"baz\"}]"; + private final String EQUALS_FILTER = "$.[?(@.foo == %s)].foo"; + private final String IN_FILTER = "$.[?(@.foo in [%s])].foo"; + private final String DOUBLE_QUOTES = "\"bar\""; + private final String DOUBLE_QUOTES_EQUALS_FILTER = String.format(EQUALS_FILTER, DOUBLE_QUOTES); + private final String DOUBLE_QUOTES_IN_FILTER = String.format(IN_FILTER, DOUBLE_QUOTES); + private final String SINGLE_QUOTES = "'bar'"; + private final String SINGLE_QUOTES_EQUALS_FILTER = String.format(EQUALS_FILTER, SINGLE_QUOTES); + private final String SINGLE_QUOTES_IN_FILTER = String.format(IN_FILTER, SINGLE_QUOTES); + + + @Rule + public final ExpectedException exception = ExpectedException.none(); + + @Test + public void testJsonPathQuotesJackson() throws Exception { + final Configuration jackson = Configuration.builder().jsonProvider(new JacksonJsonProvider()).mappingProvider(new JacksonMappingProvider()).build(); + final DocumentContext ctx = JsonPath.using(jackson).parse(JSON); + + final List doubleQuoteEqualsResult = ctx.read(DOUBLE_QUOTES_EQUALS_FILTER); + assertEquals(Lists.newArrayList("bar"), doubleQuoteEqualsResult); + + final List singleQuoteEqualsResult = ctx.read(SINGLE_QUOTES_EQUALS_FILTER); + assertEquals(doubleQuoteEqualsResult, singleQuoteEqualsResult); + + final List doubleQuoteInResult = ctx.read(DOUBLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult, doubleQuoteEqualsResult); + + exception.expect(InvalidJsonException.class); + ctx.read(SINGLE_QUOTES_IN_FILTER); + } + + + @Test + public void testJsonPathQuotesJacksonJsonNode() throws Exception { + final Configuration jacksonJsonNode = Configuration.builder().jsonProvider(new JacksonJsonNodeJsonProvider()).mappingProvider(new JacksonMappingProvider()).build(); + final DocumentContext ctx = JsonPath.using(jacksonJsonNode).parse(JSON); + + final ArrayNode doubleQuoteEqualsResult = ctx.read(DOUBLE_QUOTES_EQUALS_FILTER); + assertEquals("bar", doubleQuoteEqualsResult.get(0).asText()); + + final ArrayNode singleQuoteEqualsResult = ctx.read(SINGLE_QUOTES_EQUALS_FILTER); + assertEquals(doubleQuoteEqualsResult, singleQuoteEqualsResult); + + final ArrayNode doubleQuoteInResult = ctx.read(DOUBLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult, doubleQuoteEqualsResult); + + exception.expect(InvalidJsonException.class); + ctx.read(SINGLE_QUOTES_IN_FILTER); + } + + @Test + public void testJsonPathQuotesGson() throws Exception { + final Configuration gson = Configuration.builder().jsonProvider(new GsonJsonProvider()).mappingProvider(new GsonMappingProvider()).build(); + final DocumentContext ctx = JsonPath.using(gson).parse(JSON); + + final JsonArray doubleQuoteEqualsResult = ctx.read(DOUBLE_QUOTES_EQUALS_FILTER); + assertEquals("bar", doubleQuoteEqualsResult.get(0).getAsString()); + + final JsonArray singleQuoteEqualsResult = ctx.read(SINGLE_QUOTES_EQUALS_FILTER); + assertEquals(doubleQuoteEqualsResult, singleQuoteEqualsResult); + + final JsonArray doubleQuoteInResult = ctx.read(DOUBLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult, doubleQuoteEqualsResult); + + final JsonArray singleQuoteInResult = ctx.read(SINGLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult, singleQuoteInResult); + } + + @Test + public void testJsonPathQuotesJsonOrg() throws Exception { + final Configuration jsonOrg = Configuration.builder().jsonProvider(new JsonOrgJsonProvider()).mappingProvider(new JsonOrgMappingProvider()).build(); + final DocumentContext ctx = JsonPath.using(jsonOrg).parse(JSON); + + final org.json.JSONArray doubleQuoteEqualsResult = ctx.read(DOUBLE_QUOTES_EQUALS_FILTER); + assertEquals("bar", doubleQuoteEqualsResult.get(0)); + + final org.json.JSONArray singleQuoteEqualsResult = ctx.read(SINGLE_QUOTES_EQUALS_FILTER); + assertEquals(doubleQuoteEqualsResult.get(0), singleQuoteEqualsResult.get(0)); + + final org.json.JSONArray doubleQuoteInResult = ctx.read(DOUBLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult.get(0), doubleQuoteEqualsResult.get(0)); + + final org.json.JSONArray singleQuoteInResult = ctx.read(SINGLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult.get(0), singleQuoteInResult.get(0)); + } + + @Test + public void testJsonPathQuotesJsonSmart() throws Exception { + final Configuration jsonSmart = Configuration.builder().jsonProvider(new JsonSmartJsonProvider()).mappingProvider(new JsonSmartMappingProvider()).build(); + final DocumentContext ctx = JsonPath.using(jsonSmart).parse(JSON); + + final net.minidev.json.JSONArray doubleQuoteEqualsResult = ctx.read(DOUBLE_QUOTES_EQUALS_FILTER); + assertEquals("bar", doubleQuoteEqualsResult.get(0)); + + final net.minidev.json.JSONArray singleQuoteEqualsResult = ctx.read(SINGLE_QUOTES_EQUALS_FILTER); + assertEquals(doubleQuoteEqualsResult, singleQuoteEqualsResult); + + final net.minidev.json.JSONArray doubleQuoteInResult = ctx.read(DOUBLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult, doubleQuoteEqualsResult); + + final net.minidev.json.JSONArray singleQuoteInResult = ctx.read(SINGLE_QUOTES_IN_FILTER); + assertEquals(doubleQuoteInResult, singleQuoteInResult); + } +} \ No newline at end of file From 69ff849eae352e99a9e9dea8cf7fac087284248e Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Tue, 28 Mar 2017 09:14:28 +0200 Subject: [PATCH 25/25] Added copyright date and company #251. --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index d6456956..9972f34b 100644 --- a/LICENSE +++ b/LICENSE @@ -187,7 +187,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2017 Jayway Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.