diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..10f5088e6 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,39 @@ +--- +name: Java CI + +on: + push: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + java: [8, 11, 17, 18] # todo: update to latest Gradle version for Java 21 support + fail-fast: false + max-parallel: 4 + name: JDK ${{ matrix.java }} + + steps: + - uses: actions/checkout@v4 + - name: Set up JDK + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java }} + distribution: temurin + cache: 'gradle' + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Build with Gradle + run: ./gradlew build --warning-mode all + + - name: Run Tests + run: ./gradlew check + + - name: Maven Install + run: ./gradlew clean publishToMavenLocal + +... diff --git a/.gitignore b/.gitignore index 7fd04a4c5..54ff21411 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,9 @@ target .springBeans .DS_Store .gradle +.java-version TODO gradle.properties build bin/ +out/ diff --git a/.travis.yml b/.travis.yml index 32f091ba8..fbf2e7b7e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,12 @@ language: java sudo: false jdk: - - oraclejdk7 + - openjdk8 cache: directories: - $HOME/.gradle + +arch: + - amd64 + - ppc64le diff --git a/README.md b/README.md index 68fa76a8f..9a21e885a 100644 --- a/README.md +++ b/README.md @@ -5,29 +5,10 @@ Jayway JsonPath [![Build Status](https://travis-ci.org/json-path/JsonPath.svg?branch=master)](https://travis-ci.org/json-path/JsonPath) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.jayway.jsonpath/json-path/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.jayway.jsonpath/json-path) -[![Javadoc](https://javadoc-emblem.rhcloud.com/doc/com.jayway.jsonpath/json-path/badge.svg)](http://www.javadoc.io/doc/com.jayway.jsonpath/json-path) +[![Javadoc](https://www.javadoc.io/badge/com.jayway.jsonpath/json-path.svg)](http://www.javadoc.io/doc/com.jayway.jsonpath/json-path) Jayway JsonPath is a Java port of [Stefan Goessner JsonPath implementation](http://goessner.net/articles/JsonPath/). -News ----- -05 Jul 2017 - Released JsonPath 2.4.0 - -26 Jun 2017 - Released JsonPath 2.3.0 - -29 Feb 2016 - Released JsonPath 2.2.0 - -22 Nov 2015 - Released JsonPath 2.1.0 - -19 Mar 2015 - Released JsonPath 2.0.0 - -11 Nov 2014 - Released JsonPath 1.2.0 - -01 Oct 2014 - Released JsonPath 1.1.0 - -26 Sep 2014 - Released JsonPath 1.0.0 - - Getting Started --------------- @@ -37,7 +18,7 @@ JsonPath is available at the Central Maven Repository. Maven users add this to y com.jayway.jsonpath json-path - 2.3.0 + 2.9.0 ``` @@ -77,34 +58,42 @@ Functions Functions can be invoked at the tail end of a path - the input to a function is the output of the path expression. The function output is dictated by the function itself. -| Function | Description | Output | -| :------------------------ | :----------------------------------------------------------------- |-----------| -| min() | Provides the min value of an array of numbers | Double | -| max() | Provides the max value of an array of numbers | Double | -| avg() | Provides the average value of an array of numbers | Double | -| stddev() | Provides the standard deviation value of an array of numbers | Double | -| length() | Provides the length of an array | Integer | - +| Function | Description | Output type | +|:------------|:-------------------------------------------------------------------------------------|:---------------------| +| `min()` | Provides the min value of an array of numbers | Double | +| `max()` | Provides the max value of an array of numbers | Double | +| `avg()` | Provides the average value of an array of numbers | Double | +| `stddev()` | Provides the standard deviation value of an array of numbers | Double | +| `length()` | Provides the length of an array | Integer | +| `sum()` | Provides the sum value of an array of numbers | Double | +| `keys()` | Provides the property keys (An alternative for terminal tilde `~`) | `Set` | +| `concat(X)` | Provides a concatinated version of the path output with a new item | like input | +| `append(X)` | add an item to the json path output array | like input | +| `first()` | Provides the first item of an array | Depends on the array | +| `last()` | Provides the last item of an array | Depends on the array | +| `index(X)` | Provides the item of an array of index: X, if the X is negative, take from backwards | Depends on the array | Filter Operators ----------------- Filters are logical expressions used to filter arrays. A typical filter would be `[?(@.age > 18)]` where `@` represents the current item being processed. More complex filters can be created with logical operators `&&` and `||`. String literals must be enclosed by single or double quotes (`[?(@.color == 'blue')]` or `[?(@.color == "blue")]`). -| Operator | Description | -| :----------------------- | :---------------------------------------------------------------- | -| == | left is equal to right (note that 1 is not equal to '1') | -| != | left is not equal to right | -| < | left is less than right | -| <= | left is less or equal to right | -| > | left is greater than right | -| >= | left is greater than or equal to right | -| =~ | left matches regular expression [?(@.name =~ /foo.*?/i)] | -| in | left exists in right [?(@.size in ['S', 'M'])] | -| nin | left does not exists in right | -| subsetof | left is a subset of right [?(@.sizes subsetof ['S', 'M', 'L'])] | -| size | size of left (array or string) should match right | -| empty | left (array or string) should be empty | +| Operator | Description | +| :----------------------- | :-------------------------------------------------------------------- | +| `==` | left is equal to right (note that 1 is not equal to '1') | +| `!=` | left is not equal to right | +| `<` | left is less than right | +| `<=` | left is less or equal to right | +| `>` | left is greater than right | +| `>=` | left is greater than or equal to right | +| `=~` | left matches regular expression [?(@.name =~ /foo.*?/i)] | +| `in` | left exists in right [?(@.size in ['S', 'M'])] | +| `nin` | left does not exists in right | +| `subsetof` | left is a subset of right [?(@.sizes subsetof ['S', 'M', 'L'])] | +| `anyof` | left has an intersection with right [?(@.sizes anyof ['M', 'L'])] | +| `noneof` | left has no intersection with right [?(@.sizes noneof ['M', 'L'])] | +| `size` | size of left (array or string) should match right | +| `empty` | left (array or string) should be empty | Path Examples @@ -152,25 +141,25 @@ Given the json } ``` -| JsonPath (click link to try)| Result | -| :------- | :----- | -| $.store.book[*].author| The authors of all books | -| $..author | All authors | -| $.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) | -| $..book[-2:] | Last two books | -| $..book[2:] | Book number two from tail | -| $..book[?(@.isbn)] | All books with an ISBN number | -| $.store.book[?(@.price < 10)] | All books in store cheaper than 10 | -| $..book[?(@.price <= $['expensive'])] | All books in store that are not "expensive" | -| $..book[?(@.author =~ /.*REES/i)] | All books matching regex (ignore case) | -| $..* | Give me every thing -| $..book.length() | The number of books | +| JsonPath | Result | +|:-------------------------------------------------------------------| :----- | +| `$.store.book[*].author` | The authors of all books | +| `$..author` | All authors | +| `$.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) | +| `$..book[-2:]` | Last two books | +| `$..book[2:]` | All books from index 2 (inclusive) to last | +| `$..book[?(@.isbn)]` | All books with an ISBN number | +| `$.store.book[?(@.price < 10)]` | All books in store cheaper than 10 | +| `$..book[?(@.price <= $['expensive'])]` | All books in store that are not "expensive" | +| `$..book[?(@.author =~ /.*REES/i)]` | All books matching regex (ignore case) | +| `$..*` | Give me every thing +| `$..book.length()` | The number of books | Reading a Document ------------------ @@ -216,10 +205,10 @@ try to cast the result to the type expected by the invoker. ```java //Will throw an java.lang.ClassCastException -List list = JsonPath.parse(json).read("$.store.book[0].author") +List list = JsonPath.parse(json).read("$.store.book[0].author"); //Works fine -String author = JsonPath.parse(json).read("$.store.book[0].author") +String author = JsonPath.parse(json).read("$.store.book[0].author"); ``` When evaluating a path you need to understand the concept of when a path is `definite`. A path is `indefinite` if it contains: @@ -239,13 +228,13 @@ String json = "{\"date_as_long\" : 1411455611975}"; Date date = JsonPath.parse(json).read("$['date_as_long']", Date.class); ``` -If you configure JsonPath to use `JacksonMappingProvider` or GsonMappingProvider` you can even map your JsonPath output directly into POJO's. +If you configure JsonPath to use `JacksonMappingProvider`, `GsonMappingProvider`, or `JakartaJsonProvider` you can even map your JsonPath output directly into POJO's. ```java Book book = JsonPath.parse(json).read("$.store.book[0]", Book.class); ``` -To obtainin full generics type information, use TypeRef. +To obtain full generics type information, use TypeRef. ```java TypeRef> typeRef = new TypeRef>() {}; @@ -322,7 +311,7 @@ List> books = Path vs Value ------------- -In the Goessner implementation a JsonPath can return either `Path` or `Value`. `Value` is the default and what all the examples above are returning. If you rather have the path of the elements our query is hitting this can be acheived with an option. +In the Goessner implementation a JsonPath can return either `Path` or `Value`. `Value` is the default and what all the examples above are returning. If you rather have the path of the elements our query is hitting this can be achieved with an option. ```java Configuration conf = Configuration.builder() @@ -337,6 +326,15 @@ assertThat(pathList).containsExactly( "$['store']['book'][3]['author']"); ``` +Set a value +----------- +The library offers the possibility to set a value. + +```java +String newJson = JsonPath.parse(json).set("$['store']['book'][0]['author']", "Paul").jsonString(); +``` + + Tweaking Configuration ---------------------- @@ -383,10 +381,13 @@ This option configures JsonPath to return a list even when the path is `definite ```java Configuration conf = Configuration.defaultConfiguration(); -//Works fine +//ClassCastException thrown List genders0 = JsonPath.using(conf).parse(json).read("$[0]['gender']"); -//PathNotFoundException thrown -List genders1 = JsonPath.using(conf).parse(json).read("$[1]['gender']"); + +Configuration conf2 = conf.addOptions(Option.ALWAYS_RETURN_LIST); + +//Works fine +List genders0 = JsonPath.using(conf2).parse(json).read("$[0]['gender']"); ``` **SUPPRESS_EXCEPTIONS**
@@ -395,20 +396,35 @@ This option makes sure no exceptions are propagated from path evaluation. It fol * If option `ALWAYS_RETURN_LIST` is present an empty list will be returned * If option `ALWAYS_RETURN_LIST` is **NOT** present null returned +**REQUIRE_PROPERTIES** +
+This option configures JsonPath to require properties defined in path when an `indefinite` path is evaluated. + +```java +Configuration conf = Configuration.defaultConfiguration(); + +//Works fine +List genders = JsonPath.using(conf).parse(json).read("$[*]['gender']"); + +Configuration conf2 = conf.addOptions(Option.REQUIRE_PROPERTIES); + +//PathNotFoundException thrown +List genders = JsonPath.using(conf2).parse(json).read("$[*]['gender']"); +``` ### JsonProvider SPI -JsonPath is shipped with three different JsonProviders: +JsonPath is shipped with five different JsonProviders: -* [JsonSmartJsonProvider](https://code.google.com/p/json-smart/) (default) +* [JsonSmartJsonProvider](https://github.com/netplex/json-smart-v2) (default) * [JacksonJsonProvider](https://github.com/FasterXML/jackson) * [JacksonJsonNodeJsonProvider](https://github.com/FasterXML/jackson) * [GsonJsonProvider](https://code.google.com/p/google-gson/) -* [JsonOrgJsonProvider](http://www.json.org/java/index.html) +* [JsonOrgJsonProvider](https://github.com/stleary/JSON-java) +* [JakartaJsonProvider](https://javaee.github.io/jsonp/) Changing the configuration defaults as demonstrated should only be done when your application is being initialized. Changes during runtime is strongly discouraged, especially in multi threaded applications. - ```java Configuration.setDefaults(new Configuration.Defaults() { @@ -434,6 +450,16 @@ Configuration.setDefaults(new Configuration.Defaults() { Note that the JacksonJsonProvider requires `com.fasterxml.jackson.core:jackson-databind:2.4.5` and the GsonJsonProvider requires `com.google.code.gson:gson:2.3.1` on your classpath. +Both of Jakarta EE 9 [JSON-P (JSR-342)](https://javaee.github.io/jsonp/) and [JSON-B (JSR-367)](http://json-b.net/) providers expect at least Java 8 and require compatible JSON API implementations (such as [Eclipse Glassfish](https://projects.eclipse.org/projects/ee4j.jsonp) and [Eclipse Yasson](https://projects.eclipse.org/projects/ee4j.yasson)) on application runtime classpath; such implementations may also be provided by Java EE application container. Please also note that Apache Johnzon is not classpath-compatible with Jakarta EE 9 specification yet, and if JSON-B mapping provider is chosen then JSON-P provider must be configured and used, too. + +One peculiarity of Jakarta EE 9 specifications for JSON processing and databinding (mapping) is immutability of Json arrays and objects as soon as they are fully parsed or written to. To respect the API specification, but allow JsonPath to modify Json documents through add, set/put, replace, and delete operations, `JakartaJsonProvider` has to be initiliazed with optional `true` argument: + +* `JsonProvider jsonProvider = new JakartaJsonProvider(true)` (enable mutable Json arrays and objects) +* `JsonProvider jsonProvider = new JakartaJsonProvider()` (default, strict JSON-P API compliance) + +All lookup and read operations with JsonPath are supported regardless of initilization mode. Default mode also needs less memory and is more performant. + + ### Cache SPI In JsonPath 2.1.0 a new Cache SPI was introduced. This allows API consumers to configure path caching in a way that suits their needs. The cache must be configured before it is accesses for the first time or a JsonPathException is thrown. JsonPath ships with two cache implementations @@ -466,4 +492,3 @@ CacheProvider.setCache(new Cache() { [![Analytics](https://ga-beacon.appspot.com/UA-54945131-1/jsonpath/index)](https://github.com/igrigorik/ga-beacon) - diff --git a/build.gradle b/build.gradle index 6a96ca466..3cd206c0b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,29 +1,51 @@ buildscript { repositories { - jcenter() + mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'me.champeau.gradle:gradle-javadoc-hotfix-plugin:0.1' - classpath 'com.github.jengelman.gradle.plugins:shadow:1.2.3' - classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.1.0' + classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0' + classpath 'biz.aQute.bnd:biz.aQute.bnd.gradle:6.1.0' } } ext { libs = [ - slf4jApi: 'org.slf4j:slf4j-api:1.7.25', - 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', - jsonOrg: 'org.json:json:20140107', - tapestryJson: 'org.apache.tapestry:tapestry-json:5.4.3', - hamcrestCore: 'org.hamcrest:hamcrest-core:1.3', - hamcrestLibrary: 'org.hamcrest:hamcrest-library:1.3', - - test: ['org.slf4j:slf4j-simple:1.7.16', 'org.assertj:assertj-core:2.1.0', 'commons-io:commons-io:2.4','org.hamcrest:hamcrest-core:1.3', 'org.hamcrest:hamcrest-library:1.3', 'junit:junit:4.12'] + jsonSmart: 'net.minidev:json-smart:2.5.0', + slf4jApi: 'org.slf4j:slf4j-api:2.0.11', + gson: 'com.google.code.gson:gson:2.10.1', + hamcrest: 'org.hamcrest:hamcrest:2.2', + jacksonDatabind: 'com.fasterxml.jackson.core:jackson-databind:2.16.1', + jettison: 'org.codehaus.jettison:jettison:1.5.4', + jsonOrg: 'org.json:json:20231013', + tapestryJson: 'org.apache.tapestry:tapestry-json:5.8.3', + jakartaJsonP: 'jakarta.json:jakarta.json-api:2.0.2', + jakartaJsonB: 'jakarta.json.bind:jakarta.json.bind-api:2.0.0', + + test: [ + 'commons-io:commons-io:2.15.0', + 'junit:junit:4.13.+', + 'org.junit.vintage:junit-vintage-engine:5.10.+', + 'org.assertj:assertj-core:3.25.1', + 'org.hamcrest:hamcrest:2.2', + 'org.glassfish:jakarta.json:2.0.1', + 'org.eclipse:yasson:2.0.4', + //'org.apache.johnzon:johnzon-jsonb:1.2.21', + 'org.slf4j:slf4j-simple:2.0.9', + 'com.google.code.gson:gson:2.10.1', + 'org.hamcrest:hamcrest:2.2', + 'com.fasterxml.jackson.core:jackson-databind:2.16.1', + 'org.codehaus.jettison:jettison:1.5.4', + 'org.json:json:20231013', + 'org.apache.tapestry:tapestry-json:5.8.3', + 'jakarta.json:jakarta.json-api:2.0.2', + 'jakarta.json.bind:jakarta.json.bind-api:2.0.0' + + ] ] - snapshotVersion = false + snapshotVersion = true } allprojects { @@ -31,51 +53,110 @@ allprojects { ext.buildTimestamp = new Date().format('yyyy-MM-dd HH:mm:ss') group = 'com.jayway.jsonpath' - version = '2.4.0' + (snapshotVersion ? "-SNAPSHOT" : "") + version = '2.9.0' + (snapshotVersion ? "-SNAPSHOT" : "") - if (JavaVersion.current().isJava8Compatible()) { - tasks.withType(Javadoc) { - options.addStringOption('Xdoclint:none', '-quiet') - } - } } subprojects { apply plugin: 'java' + apply plugin: 'java-library' + apply plugin: 'maven-publish' apply plugin: 'signing' - apply plugin: 'osgi' + apply plugin: 'biz.aQute.bnd.builder' - sourceCompatibility = 1.6 - targetCompatibility = 1.6 + java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } repositories { mavenCentral() } - task javadocJar(type: Jar) { - classifier = 'javadoc' - from javadoc + java { + withJavadocJar() + withSourcesJar() } - task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allSource + test { + useJUnitPlatform() + + systemProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager") + + testLogging { + events "passed", "skipped", "failed" + } } signing { - required { !snapshotVersion && gradle.taskGraph.hasTask("uploadArchives") } - sign configurations.archives + sign publishing.publications + required { !snapshotVersion && gradle.taskGraph.hasTask("publish") } } - artifacts { - archives jar, javadocJar, sourcesJar + javadoc { + if (JavaVersion.current().isJava8Compatible()) { + options.addStringOption('Xdoclint:none', '-quiet') + } + + if(JavaVersion.current().isJava9Compatible()) { + options.addBooleanOption('html5', true) + } + } + + publishing { + repositories { + maven { + def releaseRepo = "https://oss.sonatype.org/service/local/staging/deploy/maven2/" + def snapshotRepo = "https://oss.sonatype.org/content/repositories/snapshots/" + url = snapshotVersion ? snapshotRepo : releaseRepo + credentials { + username = project.hasProperty('sonatypeOssUsername') ? sonatypeOssUsername : "Unknown user" + password = project.hasProperty('sonatypeOssPassword') ? sonatypeOssPassword : "Unknown password" + } + } + } + publications { + mavenJava(MavenPublication) { + from components.java + + artifactId = jar.baseName + + pom { + name = jar.baseName + description = 'A library to query and verify JSON' + url = 'https://github.com/jayway/JsonPath' + + licenses { + license { + name = "The Apache Software License, Version 2.0" + url = "https://www.apache.org/licenses/LICENSE-2.0.txt" + distribution = "repo" + } + } + + scm { + url = 'scm:git:git://github.com/jayway/JsonPath.git' + connection = 'scm:git:git://github.com/jayway/JsonPath.git' + developerConnection = 'scm:git:git://github.com/jayway/JsonPath.git' + } + + developers { + developer { + id = 'kalle.stenflo' + name = 'Kalle Stenflo' + email = 'kalle.stenflo (a) gmail.com' + } + } + } + } + } } } -task wrapper(type: Wrapper) { - gradleVersion = '4.0' +wrapper { + gradleVersion = '7.4.2' } //Task used by Heroku for staging task stage(dependsOn: [':json-path-web-test:clean', 'json-path-web-test:jar', 'json-path-web-test:shadowJar']) {} -apply from: "$rootDir/gradle/binaryCompatibility.gradle" + diff --git a/gradle/binaryCompatibility.gradle b/gradle/binaryCompatibility.gradle index f8ef62ba5..571110012 100644 --- a/gradle/binaryCompatibility.gradle +++ b/gradle/binaryCompatibility.gradle @@ -21,11 +21,14 @@ import groovy.text.markup.TemplateConfiguration buildscript { // this block should not be necessary, but for some reason it fails without! repositories { - jcenter() + mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { - classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.1.0' + classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.4.0' } } @@ -96,7 +99,8 @@ if (JavaVersion.current().isJava7Compatible()) { subprojects { - task japicmp(type: me.champeau.gradle.ArtifactJapicmpTask) { + tasks.register("japicmp", me.champeau.gradle.japicmp.JapicmpTask) { + //task japicmp(type: me.champeau.gradle.ArtifactJapicmpTask) { dependsOn jar //baseline = "com.jayway.jsonpath:${project.name}:+@jar" //latest release baseline = 'com.jayway.jsonpath:json-path:2.0.0@jar' @@ -108,7 +112,6 @@ if (JavaVersion.current().isJava7Compatible()) { def htmlReportFile = file("${buildDir}/reports/binary-compat-${project.name}.html") inputs.file file("$configDir/$templateFile") - inputs.file templateFile outputs.file htmlReportFile def model = [title : "Binary compatibility report for ${project.name}", @@ -127,8 +130,9 @@ if (JavaVersion.current().isJava7Compatible()) { subprojects { check.dependsOn(checkBinaryCompatibility) - tasks.withType(me.champeau.gradle.ArtifactJapicmpTask) { task -> + + tasks.register("checkCompatibility", me.champeau.gradle.japicmp.JapicmpTask) { task -> checkBinaryCompatibility.dependsOn(task) } } -} \ No newline at end of file +} diff --git a/gradle/publishMaven.gradle b/gradle/publishMaven.gradle deleted file mode 100644 index 39be8ca25..000000000 --- a/gradle/publishMaven.gradle +++ /dev/null @@ -1,94 +0,0 @@ -apply plugin: "maven" - -def basePom = { - project { - name project.displayName - packaging 'bundle' - description project.description - url 'https://github.com/jayway/JsonPath' - - licenses { - license { - name "The Apache Software License, Version 2.0" - url "http://www.apache.org/licenses/LICENSE-2.0.txt" - distribution "repo" - } - } - - scm { - url 'scm:git:git://github.com/jayway/JsonPath.git' - connection 'scm:git:git://github.com/jayway/JsonPath.git' - developerConnection 'scm:git:git://github.com/jayway/JsonPath.git' - } - - developers { - developer { - id 'kalle.stenflo' - name 'Kalle Stenflo' - email 'kalle.stenflo (a) gmail.com' - } - } - } -} - -def deployers = [] - -project.afterEvaluate { - configure(deployers) { - pom basePom - } -} - -install { - deployers << repositories.mavenInstaller -} - -uploadArchives { - deployers << repositories.mavenDeployer { - if (snapshotVersion) { - snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { - if (project.hasProperty("sonatypeOssUsername")) { - authentication(userName: sonatypeOssUsername, password: sonatypeOssPassword) - } - } - } else { - repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { - if (project.hasProperty("sonatypeOssUsername")) { - authentication(userName: sonatypeOssUsername, password: sonatypeOssPassword) - } - } - } - } -} - -def poms = deployers*.pom -def optionalDeps = [] -def providedDeps = [] -def internalDeps = [] - -ext { - modifyPom = { Closure modification -> - poms.each { - it.whenConfigured(modification) - } - } - optional = { optionalDeps << it; it } - provided = { providedDeps << it; it } - internal = { internalDeps << it; it } -} - -modifyPom { pom -> - optionalDeps.each { dep -> - pom.dependencies.find { it.artifactId == dep.name }.optional = true - } - providedDeps.each { dep -> - pom.dependencies.find { it.artifactId == dep.name }.scope = "provided" - } - internalDeps.each { dep -> - pom.dependencies.removeAll { it.artifactId == dep.name } - } - // no need to publish test dependencies - pom.dependencies.removeAll { it.scope == "test" } -} - -deployers*.beforeDeployment { signing.signPom(it) } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a772446ab..41d9927a4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index beae58122..aa991fcea 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Fri Jun 23 10:27:01 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-bin.zip diff --git a/gradlew b/gradlew index cccdd3d51..1b6c78733 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,129 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original 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 +# +# https://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. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # 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 +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${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="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -89,84 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -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 - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -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 +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index e95643d6a..ac1b06f93 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @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 DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/json-path-assert/README.md b/json-path-assert/README.md index a56b9a510..8e48c3469 100644 --- a/json-path-assert/README.md +++ b/json-path-assert/README.md @@ -11,7 +11,7 @@ This library is available at the Central Maven Repository. Maven users add this com.jayway.jsonpath json-path-assert - 2.2.0 + 2.6.0 ``` diff --git a/json-path-assert/build.gradle b/json-path-assert/build.gradle index f63e70bb5..bad553215 100644 --- a/json-path-assert/build.gradle +++ b/json-path-assert/build.gradle @@ -1,19 +1,19 @@ -apply from: "$rootDir/gradle/publishMaven.gradle" description = "Assertions on Json using JsonPath" jar { baseName 'json-path-assert' - manifest { - attributes 'Implementation-Title': 'json-path-assert', 'Implementation-Version': version - } + bnd ( + 'Implementation-Title': 'json-path-assert', 'Implementation-Version': archiveVersion + ) } dependencies { - compile project(':json-path') - compile libs.hamcrestCore - compile libs.hamcrestLibrary - compile libs.slf4jApi + implementation project(':json-path') + implementation libs.hamcrest + implementation libs.slf4jApi - testCompile libs.test + testImplementation libs.jsonSmart + testImplementation libs.test + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAsserter.java b/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAsserter.java index 2a152fbbf..e420fc9de 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAsserter.java +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/JsonAsserter.java @@ -22,11 +22,11 @@ public interface JsonAsserter { JsonAsserter assertThat(String path, Matcher matcher); /** - * @param path - * @param matcher - * @param message - * @param - * @return + * @param path the json path specifying the value being compared + * @param matcher an expression, built of Matchers, specifying allowed values + * @param message the explanation message + * @param the static type that should be returned by the path + * @return this to allow fluent assertion chains */ JsonAsserter assertThat(String path, Matcher matcher, String message); diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java index c4b7c1df7..2a80384c7 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsCollectionWithSize.java @@ -30,7 +30,6 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING package com.jayway.jsonassert.impl.matcher; import org.hamcrest.Description; -import org.hamcrest.Factory; import org.hamcrest.Matcher; import java.util.Collection; @@ -52,6 +51,7 @@ public boolean matchesSafely(Collection item) { return sizeMatcher.matches(item.size()); } + @Override public void describeTo(Description description) { description.appendText("a collection with size ") .appendDescriptionOf(sizeMatcher); @@ -60,7 +60,6 @@ public void describeTo(Description description) { /** * Does collection size satisfy a given matcher? */ - @Factory public static Matcher> hasSize(Matcher size) { return new IsCollectionWithSize(size); } @@ -71,9 +70,8 @@ public static Matcher> hasSize(Matcher Matcher> hasSize(int size) { Matcher matcher = equalTo(size); return IsCollectionWithSize.hasSize(matcher); } -} \ No newline at end of file +} diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java index 23b12d076..2f4ec211b 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsEmptyCollection.java @@ -30,7 +30,6 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING package com.jayway.jsonassert.impl.matcher; import org.hamcrest.Description; -import org.hamcrest.Factory; import org.hamcrest.Matcher; import java.util.Collection; @@ -45,6 +44,7 @@ public boolean matchesSafely(Collection item) { return item.isEmpty(); } + @Override public void describeTo(Description description) { description.appendText("an empty collection"); } @@ -52,8 +52,7 @@ public void describeTo(Description description) { /** * Matches an empty collection. */ - @Factory public static Matcher> empty() { return new IsEmptyCollection(); } -} \ No newline at end of file +} diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java index 976694496..c24671684 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingKey.java @@ -30,7 +30,6 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING package com.jayway.jsonassert.impl.matcher; import org.hamcrest.Description; -import org.hamcrest.Factory; import org.hamcrest.Matcher; import java.util.Map; @@ -54,17 +53,16 @@ public boolean matchesSafely(Map item) { return false; } + @Override public void describeTo(Description description) { description.appendText("map with key ") .appendDescriptionOf(keyMatcher); } - @Factory public static Matcher> hasKey(K key) { return hasKey(equalTo(key)); } - @Factory public static Matcher> hasKey(Matcher keyMatcher) { return new IsMapContainingKey(keyMatcher); } diff --git a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java index 9fb3a6d0c..d60462b42 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java +++ b/json-path-assert/src/main/java/com/jayway/jsonassert/impl/matcher/IsMapContainingValue.java @@ -30,7 +30,6 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING package com.jayway.jsonassert.impl.matcher; import org.hamcrest.Description; -import org.hamcrest.Factory; import org.hamcrest.Matcher; import java.util.Map; @@ -54,17 +53,16 @@ public boolean matchesSafely(Map item) { return false; } + @Override public void describeTo(Description description) { description.appendText("map with value ") .appendDescriptionOf(valueMatcher); } - @Factory public static Matcher> hasValue(V value) { return IsMapContainingValue.hasValue(equalTo(value)); } - @Factory public static Matcher> hasValue(Matcher valueMatcher) { return new IsMapContainingValue(valueMatcher); } diff --git a/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/WithJsonPath.java b/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/WithJsonPath.java index 73acaaad0..ca570d336 100644 --- a/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/WithJsonPath.java +++ b/json-path-assert/src/main/java/com/jayway/jsonpath/matchers/WithJsonPath.java @@ -38,7 +38,7 @@ public void describeTo(Description description) { @Override protected void describeMismatchSafely(ReadContext context, Description mismatchDescription) { try { - T value = jsonPath.read(context.json()); + T value = jsonPath.read(context.jsonString()); mismatchDescription .appendText("json path ") .appendValue(jsonPath.getPath()) diff --git a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/HasNoJsonPathTest.java b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/HasNoJsonPathTest.java index edd4ca9ec..b463742d7 100644 --- a/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/HasNoJsonPathTest.java +++ b/json-path-assert/src/test/java/com/jayway/jsonpath/matchers/HasNoJsonPathTest.java @@ -8,6 +8,7 @@ public class HasNoJsonPathTest { private static final String JSON_STRING = "{" + + "\"none\": null," + "\"name\": \"Jessie\"" + "}"; @@ -21,6 +22,11 @@ public void shouldNotMatchExistingJsonPath() { assertThat(JSON_STRING, not(hasNoJsonPath("$.name"))); } + @Test + public void shouldNotMatchExplicitNull() { + assertThat(JSON_STRING, not(hasNoJsonPath("$.none"))); + } + @Test public void shouldBeDescriptive() { assertThat(hasNoJsonPath("$.name"), diff --git a/json-path-web-test/build.gradle b/json-path-web-test/build.gradle index 4f3713c7f..a708daf64 100644 --- a/json-path-web-test/build.gradle +++ b/json-path-web-test/build.gradle @@ -6,6 +6,7 @@ description = "Web app that compares different JsonPath implementations." mainClassName = 'com.jayway.jsonpath.web.boot.Main' task createBuildInfoFile { + dependsOn compileJava doLast { def buildInfoFile = new File("$buildDir/classes/java/main/build-info.properties") Properties props = new Properties() @@ -18,26 +19,27 @@ task createBuildInfoFile { jar { dependsOn createBuildInfoFile baseName 'json-path-web-test' - manifest { - attributes 'Implementation-Title': 'json-path-web-test', - 'Implementation-Version': version, - 'Main-Class': mainClassName - } + bnd ( + 'Implementation-Title': 'json-path-web-test', + 'Implementation-Version': version, + 'Main-Class': mainClassName + ) } dependencies { - compile project(':json-path') - compile 'commons-io:commons-io:2.4' - compile libs.jacksonDatabind - compile libs.jsonSmart - compile 'io.fastjson:boon:0.33' - compile 'com.nebhale.jsonpath:jsonpath:1.2' - compile 'io.gatling:jsonpath_2.10:0.6.4' - compile 'org.eclipse.jetty:jetty-server:9.3.0.M1' - compile 'org.eclipse.jetty:jetty-webapp:9.3.0.M1' - compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.20' - compile('org.glassfish.jersey.media:jersey-media-json-jackson:2.20'){ + implementation project(':json-path') + implementation 'commons-io:commons-io:2.4' + implementation libs.slf4jApi + implementation libs.jacksonDatabind + implementation libs.jsonSmart + implementation 'io.fastjson:boon:0.33' + implementation 'com.nebhale.jsonpath:jsonpath:1.2' + implementation 'io.gatling:jsonpath_2.10:0.6.4' + implementation 'org.eclipse.jetty:jetty-server:9.3.0.M1' + implementation 'org.eclipse.jetty:jetty-webapp:9.3.0.M1' + implementation 'org.glassfish.jersey.containers:jersey-container-servlet:2.20' + implementation('org.glassfish.jersey.media:jersey-media-json-jackson:2.20'){ exclude module: 'jackson-annotations:com.fasterxml.jackson.core' exclude module: 'jackson-core:com.fasterxml.jackson.core' } diff --git a/json-path/build.gradle b/json-path/build.gradle index 812eac64d..a24d7e6e3 100644 --- a/json-path/build.gradle +++ b/json-path/build.gradle @@ -1,107 +1,27 @@ -apply from: "$rootDir/gradle/publishMaven.gradle" description = "Java port of Stefan Goessner JsonPath." 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', 'org.apache.tapestry5.json.*;resolution:=optional', 'org.codehaus.jettison.*;resolution:=optional', '*' - } + bnd ( + 'Automatic-Module-Name': 'json.path', + 'Implementation-Title': 'json-path', 'Implementation-Version': archiveVersion, + 'Import-Package': 'org.json.*;resolution:=optional, com.google.gson.*;resolution:=optional, com.fasterxml.jackson.*;resolution:=optional, org.apache.tapestry5.json.*;resolution:=optional, org.codehaus.jettison.*;resolution:=optional, jakarta.json.*;resolution:=optional, *', + 'Export-Package': 'com.jayway.jsonpath,com.jayway.jsonpath.spi,com.jayway.jsonpath.spi.cache,com.jayway.jsonpath.spi.json,com.jayway.jsonpath.spi.mapper' + ) } dependencies { - compile libs.jsonSmart - compile libs.slf4jApi - compile libs.jacksonDatabind, optional - compile libs.gson, optional - compile libs.jsonOrg, optional - compile libs.tapestryJson, optional - compile libs.jettison, optional - - testCompile libs.test -} - -task distZip(type: Zip, dependsOn: assemble) { - classifier = 'with-dependencies' - - from('build/docs') { - into 'api' - } - from(sourcesJar) { - into 'source' - } - from(jar) { - into 'lib' - } - 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') || it.file.name.contains('tapestry') } - } - from(project.configurations.compile) { - into 'lib-optional/jackson' - include { it.file.name.contains('jackson') } - } - from(project.configurations.compile) { - into 'lib-optional/gson' - include { it.file.name.contains('gson') } - } - from(project.configurations.compile) { - into 'lib-optional/jettison' - include { it.file.name.contains('jettison') } - } - from(project.configurations.compile) { - into 'lib-optional/jsonOrg' - include { it.file.name.contains('json-2') } - } - from(project.configurations.compile) { - into 'lib-optional/tapestry' - include { it.file.name.contains('tapestry') } - } -} - -task distTar(type: Tar, dependsOn: assemble) { - classifier = 'with-dependencies' - compression = Compression.GZIP - extension = 'tar.gz' - - from('build/docs') { - into 'api' - } - from(sourcesJar) { - into 'source' - } - from(jar) { - into 'lib' - } - 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') || it.file.name.contains('tapestry') } - } - from(project.configurations.compile) { - into 'lib-optional/jackson' - include { it.file.name.contains('jackson') } - } - from(project.configurations.compile) { - into 'lib-optional/gson' - include { it.file.name.contains('gson') } - } - from(project.configurations.compile) { - into 'lib-optional/jettison' - include { it.file.name.contains('jettison') } - } - from(project.configurations.compile) { - into 'lib-optional/jsonOrg' - include { it.file.name.contains('json-2') } - } - from(project.configurations.compile) { - into 'lib-optional/tapestry' - include { it.file.name.contains('tapestry') } - } -} - -task dist(){ - + implementation libs.jsonSmart + implementation libs.slf4jApi + compileOnly libs.jacksonDatabind // , optional + compileOnly libs.gson// , optional + compileOnly libs.jsonOrg// , optional + compileOnly libs.tapestryJson// , optional + compileOnly libs.jettison// , optional + compileOnly libs.jakartaJsonP// , optional + compileOnly libs.jakartaJsonB// , optional + + testImplementation libs.test + testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' } -dist.dependsOn distZip -dist.dependsOn distTar diff --git a/json-path/src/main/java/com/jayway/jsonpath/Configuration.java b/json-path/src/main/java/com/jayway/jsonpath/Configuration.java index 1a591ea8d..69427e1f0 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Configuration.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Configuration.java @@ -18,12 +18,7 @@ import com.jayway.jsonpath.spi.json.JsonProvider; import com.jayway.jsonpath.spi.mapper.MappingProvider; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Set; +import java.util.*; import static com.jayway.jsonpath.internal.Utils.notNull; import static java.util.Arrays.asList; @@ -142,7 +137,7 @@ public Configuration addOptions(Option... options) { /** * Creates a new configuration with the provided options. Options in this configuration are discarded. * @param options - * @return + * @return the new configuration instance */ public Configuration setOptions(Option... options) { return Configuration.builder().jsonProvider(jsonProvider).mappingProvider(mappingProvider).options(options).evaluationListener(evaluationListeners).build(); @@ -150,7 +145,7 @@ public Configuration setOptions(Option... options) { /** * Returns the options used by this configuration - * @return + * @return the new configuration instance */ public Set