From 1aee56b2a7e5004879931c1c33f1e2872b151eee Mon Sep 17 00:00:00 2001
From: Brian Demers
Date: Fri, 1 May 2026 00:37:10 -0400
Subject: [PATCH 01/11] Drop JDK 7, raise minimum runtime to Java 8, build with
JDK 17
- Remove all JDK 7 source/target compatibility settings
- Raise minimum required Java runtime from 7 to 8
- Set build JDK to 17; update CI to use temurin 17 for code-coverage job
- Add coveralls for all module test roots so
TestProvider.java (a test fixture instrumented by Clover) is resolved
instead of causing a 'No source found' error at report time
# Conflicts:
# .github/workflows/ci.yml
---
.github/workflows/ci.yml | 80 ++---
.../impl/security/JcaTemplateTest.groovy | 8 +-
.../impl/security/TestProvider.java} | 20 +-
install-test-jdks.sh | 63 ++++
pom.xml | 340 +++++++++++-------
5 files changed, 311 insertions(+), 200 deletions(-)
rename impl/src/test/{groovy/io/jsonwebtoken/impl/security/TestProvider.groovy => java/io/jsonwebtoken/impl/security/TestProvider.java} (50%)
create mode 100755 install-test-jdks.sh
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b607a342f..2bc7dc852 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,19 +11,27 @@ env:
MVN_CMD: ./mvnw --no-transfer-progress -B
jobs:
+ # Oracle only provides JDK 17+, so test against 17, 21, and 25
oracle:
- strategy:
- matrix:
- java: [ '17' ]
runs-on: 'ubuntu-latest'
name: jdk-${{ matrix.java }}-oracle
steps:
- uses: actions/checkout@v4
+ # Install test-only JDKs first; each call appends an entry to ~/.m2/toolchains.xml
- name: Set up JDK
- uses: actions/setup-java@v4.7.0
+ uses: actions/setup-java@v4
with:
distribution: oracle
- java-version: ${{ matrix.java }}
+ java-version: |
+ 21
+ 25
+ # Build JDK last so it ends up as the active JAVA_HOME / PATH entry
+ - name: Set up JDK 17 (build)
+ uses: actions/setup-java@v4
+ with:
+ distribution: oracle
+ java-version: '17'
+ cache: 'maven'
- name: Set up OSS Community Develocity Instance for Maven
uses: gradle/develocity-actions/setup-maven@v2.1
with:
@@ -39,55 +47,29 @@ jobs:
- name: Build
# run a full build, just as we would for a release (i.e. the `ossrh` profile), but don't use gpg
# to sign artifacts, since we don't want to mess with storing signing credentials in CI:
- run: ${{env.MVN_CMD}} verify -Possrh -Dgpg.skip=true
+ run: ${{env.MVN_CMD}} verify -Possrh -Dgpg.skip=true -P jdk-17,jdk-21,jdk-25
temurin:
- strategy:
- matrix:
- java: [ '8', '11', '17', '18' ]
runs-on: 'ubuntu-latest'
- name: jdk-${{ matrix.java }}-temurin
+ name: temurin
steps:
- uses: actions/checkout@v4
+ # Install test-only JDKs first; each call appends an entry to ~/.m2/toolchains.xml
- name: Set up JDK
uses: actions/setup-java@v4
with:
- java-version: ${{ matrix.java }}
distribution: 'temurin'
- cache: 'maven'
- check-latest: true
- - name: Set up OSS Community Develocity Instance for Maven
- uses: gradle/develocity-actions/setup-maven@v2.1
- with:
- develocity-access-key: ${{ secrets.DEVELOCITY_ACCESS_KEY }}
- - name: Install softhsm2
- run: sudo apt-get install -y softhsm2
- - name: Install opensc
- run: sudo apt-get install -y opensc
- - name: Ensure SoftHSM user configuration
- run: impl/src/test/scripts/softhsm configure
- - name: Populate SoftHSM with JJWT test keys
- run: impl/src/test/scripts/softhsm import
- - name: Build
- # run a full build, just as we would for a release (i.e. the `ossrh` profile), but don't use gpg
- # to sign artifacts, since we don't want to mess with storing signing credentials in CI:
- run: ${{env.MVN_CMD}} verify -Possrh -Dgpg.skip=true
-
- zulu:
- strategy:
- matrix:
- java: [ '7', '8', '9', '11', '12', '13', '14', '15', '16', '17', '18', '21' ]
- runs-on: 'ubuntu-latest'
- env:
- JDK_MAJOR_VERSION: ${{ matrix.java }}
- name: jdk-${{ matrix.java }}-zulu
- steps:
- - uses: actions/checkout@v4
- - name: Set up JDK
+ java-version: |
+ 8
+ 11
+ 21
+ 25
+ # Build JDK last so it ends up as the active JAVA_HOME / PATH entry
+ - name: Set up JDK 17 (build)
uses: actions/setup-java@v4
with:
- java-version: ${{ matrix.java }}
- distribution: 'zulu'
+ java-version: '17'
+ distribution: 'temurin'
cache: 'maven'
check-latest: true
- name: Set up OSS Community Develocity Instance for Maven
@@ -105,9 +87,7 @@ jobs:
- name: Build
# run a full build, just as we would for a release (i.e. the `ossrh` profile), but don't use gpg
# to sign artifacts, since we don't want to mess with storing signing credentials in CI:
- run: |
- if [ "$JDK_MAJOR_VERSION" == "7" ]; then export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=128m"; fi
- ${{env.MVN_CMD}} verify -Possrh -Dgpg.skip=true
+ run: ${{env.MVN_CMD}} verify -Possrh -Dgpg.skip=true -P jdk-8,jdk-11,jdk-17,jdk-21,jdk-25
# ensure all of our files have the correct/updated license header
license-check:
@@ -119,8 +99,8 @@ jobs:
- name: Set up JDK
uses: actions/setup-java@v4
with:
- distribution: 'zulu'
- java-version: '8'
+ distribution: 'temurin'
+ java-version: '17'
cache: 'maven'
check-latest: true
- name: Set up OSS Community Develocity Instance for Maven
@@ -133,14 +113,14 @@ jobs:
${{env.MVN_CMD}} license:check
code-coverage:
- needs: [oracle, temurin, zulu]
+ needs: [oracle, temurin]
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
- distribution: 'zulu'
+ distribution: 'temurin'
java-version: '17'
cache: 'maven'
check-latest: true
diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JcaTemplateTest.groovy b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JcaTemplateTest.groovy
index bf1037276..549df50f6 100644
--- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/JcaTemplateTest.groovy
+++ b/impl/src/test/groovy/io/jsonwebtoken/impl/security/JcaTemplateTest.groovy
@@ -266,12 +266,8 @@ class JcaTemplateTest {
template.generatePrivate(new X509EncodedKeySpec(invalid))
fail()
} catch (SecurityException expected) {
- boolean jdk11OrLater = Classes.isAvailable('java.security.interfaces.XECPrivateKey')
- String msg = 'KeyFactory callback execution failed: key spec not recognized'
- if (jdk11OrLater) {
- msg = 'KeyFactory callback execution failed: Only PKCS8EncodedKeySpec and XECPrivateKeySpec supported'
- }
- assertEquals msg, expected.getMessage()
+ String msg = expected.getMessage()
+ assertTrue msg, msg.startsWith('KeyFactory callback execution failed:')
}
}
diff --git a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestProvider.groovy b/impl/src/test/java/io/jsonwebtoken/impl/security/TestProvider.java
similarity index 50%
rename from impl/src/test/groovy/io/jsonwebtoken/impl/security/TestProvider.groovy
rename to impl/src/test/java/io/jsonwebtoken/impl/security/TestProvider.java
index 197a253ec..ce8d18aca 100644
--- a/impl/src/test/groovy/io/jsonwebtoken/impl/security/TestProvider.groovy
+++ b/impl/src/test/java/io/jsonwebtoken/impl/security/TestProvider.java
@@ -13,17 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.jsonwebtoken.impl.security
+package io.jsonwebtoken.impl.security;
-import java.security.Provider
+import java.security.Provider;
-class TestProvider extends Provider {
+/**
+ * Test-only {@link Provider} subclass. Defined in Java (not Groovy) because Groovy 4 cannot resolve
+ * the {@code protected} {@code Provider} constructor via its meta-class on JDK 17+.
+ */
+public class TestProvider extends Provider {
- TestProvider() {
- this('test')
+ public TestProvider() {
+ this("test");
}
- TestProvider(String name) {
- super(name, 1.0d, 'info')
+ public TestProvider(String name) {
+ //noinspection deprecation - double constructor used for Java 8 source compatibility;
+ // the (String, String, String) replacement was added in Java 9
+ super(name, 1.0d, "info");
}
}
diff --git a/install-test-jdks.sh b/install-test-jdks.sh
new file mode 100755
index 000000000..4aa0dc2c2
--- /dev/null
+++ b/install-test-jdks.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+# install-test-jdks.sh
+#
+# Installs all JDK versions needed to run the full multi-JDK test matrix locally via SDKMAN,
+# then generates ~/.m2/toolchains.xml from the discovered JDKs.
+#
+# Usage:
+# ./install-test-jdks.sh
+#
+# After running this script, activate each profile you want to test against, e.g.:
+# ./mvnw verify -P jdk-8,jdk-11,jdk-21,jdk-25
+#
+# The build JDK must be JDK 17+. If you are not already on JDK 17:
+# sdk use java <17.x.x-tem>
+
+set -euo pipefail
+
+# ============================================================
+# JDK versions to install.
+# Update these when new patch releases are available.
+# Find current versions with: sdk list java
+#
+# NOTE: Temurin does not provide JDK 8 on all platforms (e.g.
+# macOS/ARM). Zulu is used for JDK 8 as a reliable fallback.
+# ============================================================
+JDKS=(
+ "8.0.492-zulu" # JDK 8 - minimum supported runtime
+ "11.0.31-tem" # JDK 11
+ "17.0.19-tem" # JDK 17 - required build JDK
+ "21.0.11-tem" # JDK 21
+ "25.0.3-tem" # JDK 25
+)
+# ============================================================
+
+if ! command -v sdk &>/dev/null; then
+ echo "ERROR: SDKMAN not found. Install it from https://sdkman.io" >&2
+ exit 1
+fi
+
+# Source SDKMAN so 'sdk' commands work in this script
+# shellcheck disable=SC1090
+source "${SDKMAN_DIR:-$HOME/.sdkman}/bin/sdkman-init.sh"
+
+echo "Installing test JDKs via SDKMAN..."
+echo "(Already-installed versions will be skipped)"
+echo
+
+for jdk in "${JDKS[@]}"; do
+ sdk install java "$jdk" || true
+done
+
+echo
+echo "Done. Generating ~/.m2/toolchains.xml from discovered JDKs..."
+./mvnw --no-transfer-progress -q \
+ org.apache.maven.plugins:maven-toolchains-plugin:3.2.0:generate-jdk-toolchains-xml \
+ -Dtoolchain.file="${HOME}/.m2/toolchains.xml"
+
+echo
+echo "To run the full multi-JDK test matrix:"
+echo " ./mvnw verify -P jdk-8,jdk-11,jdk-17,jdk-21,jdk-25"
+echo
+echo "To run a single JDK profile (e.g., JDK 8 only):"
+echo " ./mvnw verify -P jdk-8"
diff --git a/pom.xml b/pom.xml
index e9eb6b1b6..c914b36be 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,16 +97,27 @@
3.3.03.11.0
- 3.1.1
+ 3.6.33.2.13.1.0
- 1.6
- 0.13.1
- 1.6.1
+ 3.1.0
+ 0.15.6
+ 3.2.0
+ 4.2.04.2.rc3true
- 7
+
+ 8
+
+ 8
+
+
+ false
+ false${user.name}-${maven.build.timestamp}2.12.7.1
@@ -114,22 +125,24 @@
2.11.0
-
1.84bcprov-jdk18onbcpkix-jdk18on
- 2.5.16
- 3.6
+ 4.0.31
+ 4.24.12
- 2.0.0-beta.5
- 3.0.0-M5
- 3.0.0-M5
- 4.3.1
+ 2.0.7
+ 3.1.2
+ 3.1.2
+ 4.3.1${jjwt.root}/target/clover/clover.db
-
+
+ false
+ ${test.addOpens}
--add-opens java.base/java.lang=ALL-UNNAMED,
--add-opens java.desktop/java.beans=ALL-UNNAMED,
@@ -211,7 +224,7 @@
- org.codehaus.groovy
+ org.apache.groovygroovy${groovy.version}test
@@ -321,7 +334,8 @@
**/*.test.override**/*.bndLICENSE
- **/mvnw
+ **/mvnw
+ **/install-test-jdks.sh**/lombok.config.gitattributes**/genkeys
@@ -363,16 +377,8 @@
${jdk.version}truefalse
- ${maven.javadoc.additionalOptions}
+ -html5 ${maven.javadoc.additionalOptions}
-
-
-
- commons-lang
- commons-lang
- 2.6
-
- org.apache.maven.plugins
@@ -497,7 +503,7 @@
org.apache.maven.pluginsmaven-enforcer-plugin
- 1.4.1
+ 3.4.1enforce-banned-dependencies
@@ -516,49 +522,30 @@
true
+
+ enforce-java-17
+
+ enforce
+
+
+
+
+
+ [17,)
+ Build requires JDK 17 or later. Use SDKMAN: sdk install java 17.x.x-tem
+
+
+ true
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
org.apache.maven.pluginsmaven-compiler-plugin${maven.compiler.version}
- ${jdk.version}
- ${jdk.version}
+ ${jdk.release.version}${project.build.sourceEncoding}
@@ -583,7 +570,7 @@
- org.codehaus.groovy
+ org.apache.groovygroovy${groovy.version}
@@ -595,6 +582,7 @@
${surefire.plugin.version}${surefire.argLine}
+ once
@@ -668,6 +656,18 @@
io.jsonwebtoken.coverallscoveralls-maven-plugin4.4.1
+
+
+
+ ${jjwt.root}/api/src/test/java
+ ${jjwt.root}/impl/src/test/java
+ ${jjwt.root}/extensions/jackson/src/test/java
+ ${jjwt.root}/extensions/gson/src/test/java
+ ${jjwt.root}/extensions/orgjson/src/test/java
+
+
+
+
- jdk7
-
- 1.7
-
-
- 3.2.2
- 3.8.1
- 20230618
- bcprov-jdk15to18
- bcpkix-jdk15to18
-
+ jdk-8
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${surefire.plugin.version}
+
+
+ test-jdk-8
+ test
+
+ ${module.skip.jdk8.tests}
+
+ [1.8,1.9),[8,9)
+
+
+
+ once
+
+
+
+
+
+
+
+
- jdk8AndLater
-
- [1.8,)
-
-
- 3.0.2
- 3.0.19
- 4.2
- 2.0.7
- 0.15.6
- 3.1.2
- 3.1.2
-
+ jdk-11
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${surefire.plugin.version}
+
+
+ test-jdk-11
+ test
+
+ ${module.skip.jdk11.tests}
+
+ [11,12)
+
+ ${test.addOpens}
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
- jdk9AndLater
-
- [1.9,)
-
-
- 3.11.0
- false
- -html5
- ${test.addOpens}, --illegal-access=debug
-
+ jdk-17
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${surefire.plugin.version}
+
+
+ test-jdk-17
+ test
+
+
+ [17,18)
+
+ ${test.addOpens}
+
+
+
+
+
+
+
+
- jdk17AndLater
-
- [17,)
-
-
- -html5
- ${test.addOpens}
-
+ jdk-21
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${surefire.plugin.version}
+
+
+ test-jdk-21
+ test
+
+
+ [21,22)
+
+ ${test.addOpens}
+
+
+
+
+
+
+
+
- jdk21AndLater
-
- [21,)
-
-
-
- 8
-
+ jdk-25
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${surefire.plugin.version}
+
+
+ test-jdk-25
+ test
+
+
+ [25,26)
+
+ ${test.addOpens}
+
+
+
+
+
+
+
docs
From 2178dc7269347b924762631af1548366b5e64ae9 Mon Sep 17 00:00:00 2001
From: Brian Demers
Date: Fri, 1 May 2026 00:51:18 -0400
Subject: [PATCH 02/11] Make jdk-17 test profile active by default
Activate via property absence (!skip.jdk17.tests) so it runs in all
builds regardless of other active profiles. Suppress with
-Dskip.jdk17.tests when only other JDK profiles are needed.
---
pom.xml | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index c914b36be..d8c099f42 100644
--- a/pom.xml
+++ b/pom.xml
@@ -754,10 +754,19 @@
-
+
jdk-17
+
+
+ !skip.jdk17.tests
+
+
From 7c9a58f6ed8b6bb5c91fc53df5a9a893bebe73cd Mon Sep 17 00:00:00 2001
From: Brian Demers
Date: Fri, 1 May 2026 01:10:26 -0400
Subject: [PATCH 03/11] Replace -P jdk-N activation with -Dtest.jdk.version=N
property
Each jdk-N profile now activates via test.jdk.version=N property value
instead of requiring -P on the command line. A companion profile
skip-default-tests suppresses the default surefire execution whenever
test.jdk.version is set, so only the requested JDK runs tests.
Default build (no property): default-test runs on the build JDK.
Targeted run: ./mvnw test -Dtest.jdk.version=8|11|17|21|25
CI shape becomes uniform across all JDK matrix entries.
---
pom.xml | 64 +++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 51 insertions(+), 13 deletions(-)
diff --git a/pom.xml b/pom.xml
index d8c099f42..e53a888e6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,6 +118,9 @@
test executions (jdk-8 and jdk-11 profiles). -->
falsefalse
+
+ false${user.name}-${maven.build.timestamp}2.12.7.1
@@ -583,6 +586,7 @@
${surefire.argLine}once
+ ${skip.default.tests}
@@ -697,9 +701,29 @@
execution selects which JDK runs the tests, independently of compilation.
-->
+
+
+ skip-default-tests
+
+
+ test.jdk.version
+
+
+
+ true
+
+
+
jdk-8
+
+
+ test.jdk.version
+ 8
+
+
@@ -729,6 +753,12 @@
jdk-11
+
+
+ test.jdk.version
+ 11
+
+
@@ -742,7 +772,7 @@
${module.skip.jdk11.tests}
- [11,12)
+ 11${test.addOpens}
@@ -754,17 +784,16 @@
-
+
jdk-17
- !skip.jdk17.tests
+ test.jdk.version
+ 17
@@ -778,9 +807,6 @@
test-jdk-17test
-
- [17,18)
- ${test.addOpens}
@@ -793,6 +819,12 @@
jdk-21
+
+
+ test.jdk.version
+ 21
+
+
@@ -805,7 +837,7 @@
test
- [21,22)
+ 21${test.addOpens}
@@ -819,6 +851,12 @@
jdk-25
+
+
+ test.jdk.version
+ 25
+
+
@@ -831,7 +869,7 @@
test
- [25,26)
+ 25${test.addOpens}
From 0c9a335f30789bce93312600dbfac8cdeb017e01 Mon Sep 17 00:00:00 2001
From: Les Hazlewood <121180+lhazlewood@users.noreply.github.com>
Date: Wed, 3 Jun 2026 17:47:26 -0400
Subject: [PATCH 04/11] Merge 1.0.x into drop-jdk-raise-java-build-java17
branch to prep for merge back to 1.0.x
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* Java 8 API compatibility changes (#1015)
- Upgraded dependencies and maven plugins to latest versions compatible with JDK 8+.
- Remove JDK 7 from CI build
- Consolidated `ci.yml` build matrix
- JDK 8 through 24 build testing
- Removed `io.jsonwebtoken.impl.lang.Function` in favor of `java.util.function.Function`
- Marked API interfaces as `@FunctionalInterface` where possible
- Migrated `io.jsonwebtoken.lang.Supplier` usages to `java.util.function.Supplier` where possible, except for `RedactedSupplier` usages.
- Breaking change: Renamed and moved `io.jsonwebtoken.lang.Supplier` to `io.jsonwebtoken.security.ConfidentialValue`
- Breaking change: Renamed `GsonSupplierSerializer` to `GsonConfidentialValueSerializer`
- Breaking change: Renamed `JacksonSupplierSerializer` to `JacksonConfidentialValueSerializer`
* Declared `@FunctionalInterface` / cleanup where feasible.
* Removing explicit Java 7 and Java 8 callouts/references now that 8 is the default/baseline.
* use release for m-compiler-p and m-javadoc-p # (#1019)
* Delete duplicate comment (#1022)
* Add tests to reach 100% Clover coverage; run coverage job on JDK 17
Cover previously-uncovered branches in ProviderKey, ProviderPrivateKey,
ProvidedPrivateKeyBuilder, KeysBridge, and JcaTemplate.JcaInstanceFactory.
On macOS these branches are only exercised by Pkcs11Test (which fails locally
due to a SoftHSM2/SunPKCS11 ECDSA incompatibility), so explicit unit tests
are added to cover them on all platforms.
Switch the CI code-coverage job from Zulu JDK 8 to Temurin JDK 17, and remove
the now-unnecessary 'sleep 90s' workaround.
* Drop JDK 7, raise minimum runtime to Java 8, build with JDK 17
- Remove all JDK 7 source/target compatibility settings
- Raise minimum required Java runtime from 7 to 8
- Set build JDK to 17; update CI to use temurin 17 for code-coverage job
- Add coveralls for all module test roots so
TestProvider.java (a test fixture instrumented by Clover) is resolved
instead of causing a 'No source found' error at report time
# Conflicts:
# .github/workflows/ci.yml
* Make jdk-17 test profile active by default
Activate via property absence (!skip.jdk17.tests) so it runs in all
builds regardless of other active profiles. Suppress with
-Dskip.jdk17.tests when only other JDK profiles are needed.
* Replace -P jdk-N activation with -Dtest.jdk.version=N property
Each jdk-N profile now activates via test.jdk.version=N property value
instead of requiring -P on the command line. A companion profile
skip-default-tests suppresses the default surefire execution whenever
test.jdk.version is set, so only the requested JDK runs tests.
Default build (no property): default-test runs on the build JDK.
Targeted run: ./mvnw test -Dtest.jdk.version=8|11|17|21|25
CI shape becomes uniform across all JDK matrix entries.
* changed surefire plugin deprecated `forkMode` usages to replacement forkCount/reuseForks equivalents.
---------
Co-authored-by: Benjamin Marwell
Co-authored-by: Ignacio Piñeyro
Co-authored-by: Brian Demers
---
CHANGELOG.md | 19 +++++-
README.adoc | 51 +++++++---------
api/src/main/java/io/jsonwebtoken/Clock.java | 1 +
.../java/io/jsonwebtoken/Identifiable.java | 1 +
.../main/java/io/jsonwebtoken/JwtParser.java | 1 -
api/src/main/java/io/jsonwebtoken/Jwts.java | 20 ++-----
.../main/java/io/jsonwebtoken/Locator.java | 1 +
.../io/jsonwebtoken/io/Base64Decoder.java | 2 +-
.../io/jsonwebtoken/io/Base64Encoder.java | 2 +-
.../io/jsonwebtoken/io/Base64UrlDecoder.java | 2 +-
.../io/jsonwebtoken/io/Base64UrlEncoder.java | 2 +-
.../main/java/io/jsonwebtoken/io/Decoder.java | 1 +
.../java/io/jsonwebtoken/io/Decoders.java | 4 +-
.../main/java/io/jsonwebtoken/io/Encoder.java | 1 +
.../java/io/jsonwebtoken/io/Encoders.java | 4 +-
.../java/io/jsonwebtoken/lang/Builder.java | 1 +
.../java/io/jsonwebtoken/lang/Conjunctor.java | 1 +
.../security/AssociatedDataSupplier.java | 1 +
.../ConfidentialValue.java} | 19 +++---
.../jsonwebtoken/security/DigestSupplier.java | 1 +
.../io/jsonwebtoken/security/IvSupplier.java | 1 +
.../java/io/jsonwebtoken/security/Jwk.java | 11 ++--
.../java/io/jsonwebtoken/security/Jwks.java | 3 +-
.../security/KeyBuilderSupplier.java | 1 +
.../security/KeyLengthSupplier.java | 1 +
.../security/KeyOperationPolicied.java | 1 +
.../security/KeyOperationPolicy.java | 1 -
.../security/KeyPairBuilderSupplier.java | 1 +
.../io/jsonwebtoken/security/KeySupplier.java | 1 +
.../io/jsonwebtoken/security/Message.java | 1 +
...a => GsonConfidentialValueSerializer.java} | 10 ++--
.../jsonwebtoken/gson/io/GsonSerializer.java | 18 +++---
.../gson/io/GsonSerializerTest.groovy | 13 ++--
...> JacksonConfidentialValueSerializer.java} | 14 ++---
.../jackson/io/JacksonDeserializer.java | 3 +-
.../jackson/io/JacksonSerializer.java | 2 +-
...sonConfidentialValueSerializerTest.groovy} | 9 +--
.../jackson/io/JacksonDeserializerTest.groovy | 13 +---
...er.groovy => TestConfidentialValue.groovy} | 9 +--
.../orgjson/io/OrgJsonSerializer.java | 6 +-
.../orgjson/io/OrgJsonSerializerTest.groovy | 4 +-
.../impl/CompressionCodecLocator.java | 3 +-
.../impl/DefaultClaimsBuilder.java | 2 +-
.../jsonwebtoken/impl/DefaultJwtBuilder.java | 29 +++------
.../impl/DefaultJwtHeaderBuilder.java | 2 +-
.../jsonwebtoken/impl/DefaultJwtParser.java | 6 +-
.../impl/DefaultJwtParserBuilder.java | 2 +-
.../java/io/jsonwebtoken/impl/IdLocator.java | 3 +-
.../io/jsonwebtoken/impl/ParameterMap.java | 4 +-
.../AbstractCompressionAlgorithm.java | 2 +-
.../impl/io/ConvertingParser.java | 2 +-
.../impl/io/JsonObjectDeserializer.java | 2 +-
.../impl/lang/CheckedFunction.java | 1 +
.../impl/lang/CollectionConverter.java | 11 ++--
.../impl/lang/ConstantFunction.java | 1 +
.../impl/lang/DefaultRegistry.java | 1 +
.../impl/lang/DelegatingCheckedFunction.java | 2 +
.../impl/lang/FormattedStringFunction.java | 2 +
.../impl/lang/FormattedStringSupplier.java | 3 +-
.../io/jsonwebtoken/impl/lang/Function.java | 21 -------
.../io/jsonwebtoken/impl/lang/Functions.java | 54 ++++-------------
.../io/jsonwebtoken/impl/lang/IdRegistry.java | 10 ++--
.../impl/lang/LocatorFunction.java | 2 +
.../lang/PropagatingExceptionFunction.java | 15 ++---
...er.java => RedactedConfidentialValue.java} | 10 ++--
.../impl/lang/RedactedValueConverter.java | 9 ++-
.../impl/lang/ReflectionFunction.java | 2 +
.../impl/lang/StringRegistry.java | 3 +-
.../impl/security/AbstractJwk.java | 6 +-
.../impl/security/ConstantKeyLocator.java | 2 +-
.../security/DefaultDynamicJwkBuilder.java | 2 +-
.../security/DefaultJwkParserBuilder.java | 2 +-
.../impl/security/DefaultJwkSetBuilder.java | 2 +-
.../security/DefaultJwkSetParserBuilder.java | 2 +-
.../security/DefaultKeyOperationBuilder.java | 2 +-
.../DefaultKeyOperationPolicyBuilder.java | 2 +-
.../impl/security/EdwardsCurve.java | 2 +-
.../security/EdwardsPublicKeyDeriver.java | 2 +-
.../impl/security/JcaTemplate.java | 9 +--
.../impl/security/JwkBuilderSupplier.java | 2 +-
.../impl/security/JwkConverter.java | 2 +-
.../impl/security/JwkSetConverter.java | 2 +-
.../NamedParameterSpecValueFinder.java | 5 +-
.../impl/security/X509BuilderSupport.java | 11 +---
.../impl/lang/DefaultRegistryTest.groovy | 6 +-
.../impl/lang/FunctionsTest.groovy | 2 +
.../PropagatingExceptionFunctionTest.groovy | 2 +
...y => RedactedConfidentialValueTest.groovy} | 14 ++---
.../lang/RedactedValueConverterTest.groovy | 4 +-
.../impl/security/DefaultJwkSetTest.groovy | 10 ++--
.../impl/security/JwkSerializationTest.groovy | 16 ++---
.../impl/security/OctetJwksTest.groovy | 2 +-
.../io/jsonwebtoken/security/KeysTest.groovy | 10 +++-
pom.xml | 60 ++++++++++---------
94 files changed, 299 insertions(+), 344 deletions(-)
rename api/src/main/java/io/jsonwebtoken/{lang/Supplier.java => security/ConfidentialValue.java} (51%)
rename extensions/gson/src/main/java/io/jsonwebtoken/gson/io/{GsonSupplierSerializer.java => GsonConfidentialValueSerializer.java} (66%)
rename extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/{JacksonSupplierSerializer.java => JacksonConfidentialValueSerializer.java} (69%)
rename extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/{JacksonSupplierSerializerTest.groovy => JacksonConfidentialValueSerializerTest.groovy} (88%)
rename extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/{TestSupplier.groovy => TestConfidentialValue.groovy} (74%)
delete mode 100644 impl/src/main/java/io/jsonwebtoken/impl/lang/Function.java
rename impl/src/main/java/io/jsonwebtoken/impl/lang/{RedactedSupplier.java => RedactedConfidentialValue.java} (80%)
rename impl/src/test/groovy/io/jsonwebtoken/impl/lang/{RedactedSupplierTest.groovy => RedactedConfidentialValueTest.groovy} (68%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6503af800..b4ab4aa6c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,22 @@
## Release Notes
+### 0.14.0
+
+The first JJWT release that uses Java 8+ features. This release is not strictly backwards compatible and will also not work with Java 7.
+
+#### Backwards Compatibility Breaking Changes
+
+- The `io.jsonwebtoken.lang.Supplier` interface has been renamed and moved to `io.jsonwebtoken.security.ConfidentialValue` to avoid any potential risk of conflict or accidental use
+ with `java.util.function.Supplier`. If you have explicitly configured a `Gson` instance to work with this type previously, you must update your usage to reference the new interface, for example:
+ ```java
+ new GsonBuilder()
+ .registerTypeHierarchyAdapter(io.jsonwebtoken.security.ConfidentialValue.class, GsonConfidentialValueSerializer.INSTANCE)
+ // ... etc ...
+ .create();
+ ```
+ - The `io.jsonwebtoken.gson.io.GsonSupplierSerializer` class has been renamed to `GsonConfidentialValueSerializer`
+ - The `io.jsonwebtoken.jackson.io.JacksonSupplierSerializer` has been renamed to `JacksonConfidentialValueSerializer`.`
+
### 0.13.0
This is the last minor JJWT release branch that will support Java 7. Any necessary emergency bug fixes will be fixed in subsequent `0.13.x` patch releases, but all new development, including Java 8 compatible changes, will be in the next minor (`0.14.0`) release.
@@ -412,7 +429,7 @@ deprecate some concepts, or in some cases, completely break backwards compatibil
`GsonSupplierSerializer` type adapter, for example:
```java
new GsonBuilder()
- .registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, GsonSupplierSerializer.INSTANCE)
+ .registerTypeHierarchyAdapter(io.jsonwebtoken.security.ConfidentialValue.class, GsonSupplierSerializer.INSTANCE)
.disableHtmlEscaping().create();
```
This is to ensure JWKs have `toString()` and application log safety (do not print secure material), but still
diff --git a/README.adoc b/README.adoc
index 4ed4e1518..4ed62e940 100644
--- a/README.adoc
+++ b/README.adoc
@@ -15,7 +15,6 @@ ifdef::env-github[]
endif::[]
// Macros
-:fn-require-java8-plus: Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.
:fn-require-java11-plus: Requires Java 11 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.
:fn-require-java15-plus: Requires Java 15 or a compatible JCA Provider (like BouncyCastle) in the runtime classpath.
@@ -57,7 +56,7 @@ toc::[]
== Features
-* Fully functional on all Java 7+ JDKs and Android
+* Fully functional on all Java 8+ JDKs and Android
* Automatic security best practices and assertions
* Easy to learn and read API
* Convenient and readable http://en.wikipedia.org/wiki/Fluent_interface[fluent] interfaces, great for IDE
@@ -129,16 +128,15 @@ and conditional branch variant in the entire codebase is tested and required to
| https://www.rfc-editor.org/rfc/rfc7518.html#section-5.2.5[AES_256_CBC_HMAC_SHA_512] authenticated encryption algorithm
| `A128GCM`
-| AES GCM using 128-bit key^*1*^
+| AES GCM using 128-bit key
| `A192GCM`
-| AES GCM using 192-bit key^*1*^
+| AES GCM using 192-bit key
| `A256GCM`
-| AES GCM using 256-bit key^*1*^
+| AES GCM using 256-bit key
|===
+
-^*1*.{sp}{fn-require-java8-plus}^
* All Key Management Algorithms for obtaining JWE encryption and decryption keys:
+
@@ -179,25 +177,24 @@ and conditional branch variant in the entire codebase is tested and required to
| ECDH-ES using Concat KDF and CEK wrapped with "A256KW"
| `A128GCMKW`
-| Key wrapping with AES GCM using 128-bit key^*1*^
+| Key wrapping with AES GCM using 128-bit key
| `A192GCMKW`
-| Key wrapping with AES GCM using 192-bit key^*1*^
+| Key wrapping with AES GCM using 192-bit key
| `A256GCMKW`
-| Key wrapping with AES GCM using 256-bit key^*1*^
+| Key wrapping with AES GCM using 256-bit key
| `PBES2-HS256+A128KW`
-| PBES2 with HMAC SHA-256 and "A128KW" wrapping^*1*^
+| PBES2 with HMAC SHA-256 and "A128KW" wrapping
| `PBES2-HS384+A192KW`
-| PBES2 with HMAC SHA-384 and "A192KW" wrapping^*1*^
+| PBES2 with HMAC SHA-384 and "A192KW" wrapping
| `PBES2‑HS512+A256KW`
-| PBES2 with HMAC SHA-512 and "A256KW" wrapping^*1*^
+| PBES2 with HMAC SHA-512 and "A256KW" wrapping
|===
+
-^*1*.{sp}{fn-require-java8-plus}^
* Creating, parsing and verifying JSON Web Keys (JWKs) in all standard JWA key formats using native Java `Key` types:
+
@@ -2218,19 +2215,17 @@ The JWT specification defines 6 standard Authenticated Encryption algorithms use
| `A128GCM`
| 128
-| AES GCM using 128-bit key^*1*^
+| AES GCM using 128-bit key
| `A192GCM`
| 192
-| AES GCM using 192-bit key^*1*^
+| AES GCM using 192-bit key
| `A256GCM`
| 256
-| AES GCM using 256-bit key^*1*^
+| AES GCM using 256-bit key
|===
-^*1*.{sp}{fn-require-java8-plus}^
-
These are all represented as constants in the `io.jsonwebtoken.Jwts.ENC` registry singleton as
implementations of the `io.jsonwebtoken.security.AeadAlgorithm` interface.
@@ -2358,26 +2353,24 @@ Content Encryption Key (CEK):
| ECDH-ES using Concat KDF and CEK wrapped with "A256KW"
| `A128GCMKW`
-| Key wrapping with AES GCM using 128-bit key^*1*^
+| Key wrapping with AES GCM using 128-bit key
| `A192GCMKW`
-| Key wrapping with AES GCM using 192-bit key^*1*^
+| Key wrapping with AES GCM using 192-bit key
| `A256GCMKW`
-| Key wrapping with AES GCM using 256-bit key^*1*^
+| Key wrapping with AES GCM using 256-bit key
| `PBES2-HS256+A128KW`
-| PBES2 with HMAC SHA-256 and "A128KW" wrapping^*1*^
+| PBES2 with HMAC SHA-256 and "A128KW" wrapping
| `PBES2-HS384+A192KW`
-| PBES2 with HMAC SHA-384 and "A192KW" wrapping^*1*^
+| PBES2 with HMAC SHA-384 and "A192KW" wrapping
| `PBES2‑HS512+A256KW`
-| PBES2 with HMAC SHA-512 and "A256KW" wrapping^*1*^
+| PBES2 with HMAC SHA-512 and "A256KW" wrapping
|===
-^*1*.{sp}{fn-require-java8-plus}^
-
These are all represented as constants in the `io.jsonwebtoken.Jwts.KEY` registry singleton as
implementations of the `io.jsonwebtoken.security.KeyAlgorithm` interface.
@@ -3472,7 +3465,7 @@ If you're curious, JJWT will automatically create an internal default Gson insta
[,java]
----
new GsonBuilder()
- .registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, GsonSupplierSerializer.INSTANCE)
+ .registerTypeHierarchyAdapter(io.jsonwebtoken.security.ConfidentialValue.class, GsonConfidentialValueSerializer.INSTANCE)
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.disableHtmlEscaping()
@@ -3515,7 +3508,7 @@ And then you can specify the `GsonSerializer` using your own `Gson` instance on
Gson gson = new GsonBuilder()
// don't forget this line!:
- .registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, GsonSupplierSerializer.INSTANCE)
+ .registerTypeHierarchyAdapter(io.jsonwebtoken.security.ConfidentialValue.class, GsonConfidentialValueSerializer.INSTANCE)
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.disableHtmlEscaping().create();
@@ -3544,7 +3537,7 @@ Again, as shown above, it is critical to create your `Gson` instance using the `
[,java]
----
-.registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, GsonSupplierSerializer.INSTANCE)
+.registerTypeHierarchyAdapter(io.jsonwebtoken.security.ConfidentialValue.class, GsonConfidentialValueSerializer.INSTANCE)
----
to ensure JWK serialization works as expected.
diff --git a/api/src/main/java/io/jsonwebtoken/Clock.java b/api/src/main/java/io/jsonwebtoken/Clock.java
index 584dd605f..680251628 100644
--- a/api/src/main/java/io/jsonwebtoken/Clock.java
+++ b/api/src/main/java/io/jsonwebtoken/Clock.java
@@ -22,6 +22,7 @@
*
* @since 0.7.0
*/
+@FunctionalInterface
public interface Clock {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/Identifiable.java b/api/src/main/java/io/jsonwebtoken/Identifiable.java
index 88725715c..a8085220b 100644
--- a/api/src/main/java/io/jsonwebtoken/Identifiable.java
+++ b/api/src/main/java/io/jsonwebtoken/Identifiable.java
@@ -81,6 +81,7 @@
*
* @since 0.12.0
*/
+@FunctionalInterface
public interface Identifiable {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/JwtParser.java b/api/src/main/java/io/jsonwebtoken/JwtParser.java
index df7e173b8..2f132e360 100644
--- a/api/src/main/java/io/jsonwebtoken/JwtParser.java
+++ b/api/src/main/java/io/jsonwebtoken/JwtParser.java
@@ -22,7 +22,6 @@
import java.io.InputStream;
/**
- * A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT.
* A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT.
*
* @since 0.1
diff --git a/api/src/main/java/io/jsonwebtoken/Jwts.java b/api/src/main/java/io/jsonwebtoken/Jwts.java
index 3e425bb34..eed9bca1b 100644
--- a/api/src/main/java/io/jsonwebtoken/Jwts.java
+++ b/api/src/main/java/io/jsonwebtoken/Jwts.java
@@ -19,7 +19,6 @@
import io.jsonwebtoken.lang.Builder;
import io.jsonwebtoken.lang.Classes;
import io.jsonwebtoken.lang.Registry;
-import io.jsonwebtoken.lang.Supplier;
import io.jsonwebtoken.security.AeadAlgorithm;
import io.jsonwebtoken.security.KeyAlgorithm;
import io.jsonwebtoken.security.KeyPairBuilderSupplier;
@@ -35,6 +34,7 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Map;
+import java.util.function.Supplier;
/**
* Factory class useful for creating instances of JWT interfaces. Using this factory class can be a good
@@ -121,34 +121,22 @@ private ENC() {
/**
* "AES GCM using 128-bit key" as defined by
- * RFC 7518, Section 5.31. This
+ * RFC 7518, Section 5.3. This
* algorithm requires a 128-bit (16 byte) key.
- *
- *
1 Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime
- * classpath. If on Java 7 or earlier, BouncyCastle will be used automatically if found in the runtime
- * classpath.
*/
public static final AeadAlgorithm A128GCM = get().forKey("A128GCM");
/**
* "AES GCM using 192-bit key" as defined by
- * RFC 7518, Section 5.31. This
+ * RFC 7518, Section 5.3. This
* algorithm requires a 192-bit (24 byte) key.
- *
- *
1 Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime
- * classpath. If on Java 7 or earlier, BouncyCastle will be used automatically if found in the runtime
- * classpath.
*/
public static final AeadAlgorithm A192GCM = get().forKey("A192GCM");
/**
* "AES GCM using 256-bit key" as defined by
- * RFC 7518, Section 5.31. This
+ * RFC 7518, Section 5.3. This
* algorithm requires a 256-bit (32 byte) key.
- *
- *
1 Requires Java 8 or a compatible JCA Provider (like BouncyCastle) in the runtime
- * classpath. If on Java 7 or earlier, BouncyCastle will be used automatically if found in the runtime
- * classpath.
*/
public static final AeadAlgorithm A256GCM = get().forKey("A256GCM");
}
diff --git a/api/src/main/java/io/jsonwebtoken/Locator.java b/api/src/main/java/io/jsonwebtoken/Locator.java
index 1d22258c1..f0a0073c7 100644
--- a/api/src/main/java/io/jsonwebtoken/Locator.java
+++ b/api/src/main/java/io/jsonwebtoken/Locator.java
@@ -28,6 +28,7 @@
* @param the type of object that may be returned from the {@link #locate(Header)} method
* @since 0.12.0
*/
+@FunctionalInterface
public interface Locator {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/io/Base64Decoder.java b/api/src/main/java/io/jsonwebtoken/io/Base64Decoder.java
index e0cb96333..8a57e8a80 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Base64Decoder.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Base64Decoder.java
@@ -19,7 +19,7 @@
/**
* Very fast Base64 decoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*
* @since 0.10.0
*/
diff --git a/api/src/main/java/io/jsonwebtoken/io/Base64Encoder.java b/api/src/main/java/io/jsonwebtoken/io/Base64Encoder.java
index 6e0a6b034..249a4c4e9 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Base64Encoder.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Base64Encoder.java
@@ -19,7 +19,7 @@
/**
* Very fast Base64 encoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*
* @since 0.10.0
*/
diff --git a/api/src/main/java/io/jsonwebtoken/io/Base64UrlDecoder.java b/api/src/main/java/io/jsonwebtoken/io/Base64UrlDecoder.java
index fcca4cba5..c8a76f56b 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Base64UrlDecoder.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Base64UrlDecoder.java
@@ -17,7 +17,7 @@
/**
* Very fast Base64Url decoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*
* @since 0.10.0
*/
diff --git a/api/src/main/java/io/jsonwebtoken/io/Base64UrlEncoder.java b/api/src/main/java/io/jsonwebtoken/io/Base64UrlEncoder.java
index 1377d31e7..c2a1ca59f 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Base64UrlEncoder.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Base64UrlEncoder.java
@@ -17,7 +17,7 @@
/**
* Very fast Base64Url encoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*
* @since 0.10.0
*/
diff --git a/api/src/main/java/io/jsonwebtoken/io/Decoder.java b/api/src/main/java/io/jsonwebtoken/io/Decoder.java
index 2cf4fe896..db391c0aa 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Decoder.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Decoder.java
@@ -22,6 +22,7 @@
* @param decoding output type
* @since 0.10.0
*/
+@FunctionalInterface
public interface Decoder {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/io/Decoders.java b/api/src/main/java/io/jsonwebtoken/io/Decoders.java
index 6b7c7e66a..6c414245c 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Decoders.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Decoders.java
@@ -26,13 +26,13 @@ public final class Decoders {
/**
* Very fast Base64 decoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*/
public static final Decoder BASE64 = new ExceptionPropagatingDecoder<>(new Base64Decoder());
/**
* Very fast Base64Url decoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*/
public static final Decoder BASE64URL = new ExceptionPropagatingDecoder<>(new Base64UrlDecoder());
diff --git a/api/src/main/java/io/jsonwebtoken/io/Encoder.java b/api/src/main/java/io/jsonwebtoken/io/Encoder.java
index f334ee8c2..f07c9816b 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Encoder.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Encoder.java
@@ -22,6 +22,7 @@
* @param the type of the resulting formatted data
* @since 0.10.0
*/
+@FunctionalInterface
public interface Encoder {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/io/Encoders.java b/api/src/main/java/io/jsonwebtoken/io/Encoders.java
index 17f03f250..f3b5f9913 100644
--- a/api/src/main/java/io/jsonwebtoken/io/Encoders.java
+++ b/api/src/main/java/io/jsonwebtoken/io/Encoders.java
@@ -26,13 +26,13 @@ public final class Encoders {
/**
* Very fast Base64 encoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*/
public static final Encoder BASE64 = new ExceptionPropagatingEncoder<>(new Base64Encoder());
/**
* Very fast Base64Url encoder guaranteed to
- * work in all >= Java 7 JDK and Android environments.
+ * work in all Java JDK and Android environments.
*/
public static final Encoder BASE64URL = new ExceptionPropagatingEncoder<>(new Base64UrlEncoder());
diff --git a/api/src/main/java/io/jsonwebtoken/lang/Builder.java b/api/src/main/java/io/jsonwebtoken/lang/Builder.java
index 506c802dc..07499c82a 100644
--- a/api/src/main/java/io/jsonwebtoken/lang/Builder.java
+++ b/api/src/main/java/io/jsonwebtoken/lang/Builder.java
@@ -21,6 +21,7 @@
* @param The type of object that will be created when {@link #build()} is invoked.
* @since 0.12.0
*/
+@FunctionalInterface
public interface Builder {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/lang/Conjunctor.java b/api/src/main/java/io/jsonwebtoken/lang/Conjunctor.java
index c604752fd..b754b7220 100644
--- a/api/src/main/java/io/jsonwebtoken/lang/Conjunctor.java
+++ b/api/src/main/java/io/jsonwebtoken/lang/Conjunctor.java
@@ -22,6 +22,7 @@
* @param the type of joined object to return.
* @since 0.12.0
*/
+@FunctionalInterface
public interface Conjunctor {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/AssociatedDataSupplier.java b/api/src/main/java/io/jsonwebtoken/security/AssociatedDataSupplier.java
index 4f5cd3719..564d17ca0 100644
--- a/api/src/main/java/io/jsonwebtoken/security/AssociatedDataSupplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/AssociatedDataSupplier.java
@@ -24,6 +24,7 @@
* @see #getAssociatedData()
* @since 0.12.0
*/
+@FunctionalInterface
public interface AssociatedDataSupplier {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/lang/Supplier.java b/api/src/main/java/io/jsonwebtoken/security/ConfidentialValue.java
similarity index 51%
rename from api/src/main/java/io/jsonwebtoken/lang/Supplier.java
rename to api/src/main/java/io/jsonwebtoken/security/ConfidentialValue.java
index 7a94e591c..f0db518fc 100644
--- a/api/src/main/java/io/jsonwebtoken/lang/Supplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/ConfidentialValue.java
@@ -13,25 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package io.jsonwebtoken.lang;
+package io.jsonwebtoken.security;
/**
- * Represents a supplier of results.
+ * A wrapper for a value that should be treated as confidential. Calling {@link Object#toString()} on a
+ * {@code ConfidentialValue} instance will return the string literal <redacted>.
*
- *
There is no requirement that a new or distinct result be returned each time the supplier is invoked.
- *
- *
This interface is the equivalent of a JDK 8 {@code java.util.function.Supplier}, backported for JJWT's use in
- * JDK 7 environments.
+ *
There is no requirement that a new or distinct result be returned each time the value is invoked.
*
* @param the type of object returned by this supplier
- * @since 0.12.0
+ * @since 0.14.0, renamed and moved from {@code io.jsonwebtoken.lang.Supplier} introduced in 0.12.0
*/
-public interface Supplier {
+// MAINTAINER NOTE: do not mark this as @FunctionalInterface - it makes it easier to break the toString() contract
+public interface ConfidentialValue {
/**
- * Returns a result.
+ * Returns a confidential value that should be treated with care and not exposed unnecessarily.
*
- * @return a result.
+ * @return a confidential value that should be treated with care and not exposed unnecessarily.
*/
T get();
}
diff --git a/api/src/main/java/io/jsonwebtoken/security/DigestSupplier.java b/api/src/main/java/io/jsonwebtoken/security/DigestSupplier.java
index 4c697d9bf..d4d829e73 100644
--- a/api/src/main/java/io/jsonwebtoken/security/DigestSupplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/DigestSupplier.java
@@ -21,6 +21,7 @@
*
* @since 0.12.0
*/
+@FunctionalInterface
public interface DigestSupplier {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/IvSupplier.java b/api/src/main/java/io/jsonwebtoken/security/IvSupplier.java
index f1cc3d506..bc0c4e952 100644
--- a/api/src/main/java/io/jsonwebtoken/security/IvSupplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/IvSupplier.java
@@ -23,6 +23,7 @@
*
* @since 0.12.0
*/
+@FunctionalInterface
public interface IvSupplier {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/Jwk.java b/api/src/main/java/io/jsonwebtoken/security/Jwk.java
index fef6420aa..cd09f082b 100644
--- a/api/src/main/java/io/jsonwebtoken/security/Jwk.java
+++ b/api/src/main/java/io/jsonwebtoken/security/Jwk.java
@@ -16,7 +16,6 @@
package io.jsonwebtoken.security;
import io.jsonwebtoken.Identifiable;
-import io.jsonwebtoken.lang.Supplier;
import java.security.Key;
import java.util.Map;
@@ -49,8 +48,8 @@
*
*
JWKs often represent secret or private key data which should never be exposed publicly, nor mistakenly printed
* to application logs or {@code System.out.println} calls. As a result, all JJWT JWK
- * private or secret values are 'wrapped' in a {@link io.jsonwebtoken.lang.Supplier Supplier} instance to ensure
- * any attempt to call {@link String#toString() toString()} on the value will print a redacted value instead of an
+ * private or secret values are 'wrapped' in a {@link ConfidentialValue ConfidentialValue} instance to ensure
+ * any attempt to call {@link Object#toString() toString()} on the value will print a redacted value instead of an
* actual private or secret value.
*
*
For example, a {@link SecretJwk} will have an internal "{@code k}" member whose value reflects raw
@@ -70,11 +69,11 @@
* k=<redacted>
*
instead of the actual/raw {@code k} value.
*
- *
Finally, because all private or secret values are wrapped as {@link io.jsonwebtoken.lang.Supplier}
+ *
Finally, because all private or secret values are wrapped as {@link ConfidentialValue}
* instances, if you really wanted the real internal value, you could just call the supplier's
- * {@link Supplier#get() get()} method:
+ * {@link ConfidentialValue#get() get()} method:
*
- * String k = ((Supplier<String>)aSecretJwk.get("k")).get();
+ * String k = ((ConfidentialValue<String>)aSecretJwk.get("k")).get();
*
but BE CAREFUL: obtaining the raw value in your application code exposes greater security
* risk - you must ensure to keep that value safe and out of console or log output. It is almost always better to
* interact with the JWK's {@link #toKey() toKey()} instance directly instead of accessing
diff --git a/api/src/main/java/io/jsonwebtoken/security/Jwks.java b/api/src/main/java/io/jsonwebtoken/security/Jwks.java
index ba59847cf..0701669fa 100644
--- a/api/src/main/java/io/jsonwebtoken/security/Jwks.java
+++ b/api/src/main/java/io/jsonwebtoken/security/Jwks.java
@@ -19,7 +19,8 @@
import io.jsonwebtoken.io.Parser;
import io.jsonwebtoken.lang.Classes;
import io.jsonwebtoken.lang.Registry;
-import io.jsonwebtoken.lang.Supplier;
+
+import java.util.function.Supplier;
/**
* Utility methods for creating
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java
index d55611209..f78175863 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyBuilderSupplier.java
@@ -27,6 +27,7 @@
* @see KeyBuilder
* @since 0.12.0
*/
+@FunctionalInterface
public interface KeyBuilderSupplier> {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyLengthSupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeyLengthSupplier.java
index f550dcfd9..db50cfbe3 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyLengthSupplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyLengthSupplier.java
@@ -20,6 +20,7 @@
*
* @since 0.12.0
*/
+@FunctionalInterface
public interface KeyLengthSupplier {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java
index 49e893879..060d01b39 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicied.java
@@ -21,6 +21,7 @@
*
* @param the implementing instance for method chaining
*/
+@FunctionalInterface
public interface KeyOperationPolicied> {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java
index 60389a24b..184dd6212 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyOperationPolicy.java
@@ -38,6 +38,5 @@ public interface KeyOperationPolicy {
*
* @param ops the operations to validate
*/
- @SuppressWarnings("GrazieInspection")
void validate(Collection extends KeyOperation> ops) throws IllegalArgumentException;
}
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java
index 98d42eae6..f331fd03c 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeyPairBuilderSupplier.java
@@ -25,6 +25,7 @@
* @see KeyPairBuilder
* @since 0.12.0
*/
+@FunctionalInterface
public interface KeyPairBuilderSupplier {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/KeySupplier.java b/api/src/main/java/io/jsonwebtoken/security/KeySupplier.java
index 2026b2553..b475d40eb 100644
--- a/api/src/main/java/io/jsonwebtoken/security/KeySupplier.java
+++ b/api/src/main/java/io/jsonwebtoken/security/KeySupplier.java
@@ -23,6 +23,7 @@
* @param the type of key provided by this supplier.
* @since 0.12.0
*/
+@FunctionalInterface
public interface KeySupplier {
/**
diff --git a/api/src/main/java/io/jsonwebtoken/security/Message.java b/api/src/main/java/io/jsonwebtoken/security/Message.java
index cd5e8df16..8b9ab1dd6 100644
--- a/api/src/main/java/io/jsonwebtoken/security/Message.java
+++ b/api/src/main/java/io/jsonwebtoken/security/Message.java
@@ -23,6 +23,7 @@
* @param The type of payload in the message.
* @since 0.12.0
*/
+@FunctionalInterface
public interface Message {
/**
diff --git a/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonSupplierSerializer.java b/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonConfidentialValueSerializer.java
similarity index 66%
rename from extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonSupplierSerializer.java
rename to extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonConfidentialValueSerializer.java
index 8ae511716..a9b8e552d 100644
--- a/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonSupplierSerializer.java
+++ b/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonConfidentialValueSerializer.java
@@ -18,17 +18,17 @@
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
-import io.jsonwebtoken.lang.Supplier;
+import io.jsonwebtoken.security.ConfidentialValue;
import java.lang.reflect.Type;
-public final class GsonSupplierSerializer implements JsonSerializer> {
+public final class GsonConfidentialValueSerializer implements JsonSerializer> {
- public static final GsonSupplierSerializer INSTANCE = new GsonSupplierSerializer();
+ public static final GsonConfidentialValueSerializer INSTANCE = new GsonConfidentialValueSerializer();
@Override
- public JsonElement serialize(Supplier> supplier, Type type, JsonSerializationContext ctx) {
- Object value = supplier.get();
+ public JsonElement serialize(ConfidentialValue> confidentialValue, Type type, JsonSerializationContext ctx) {
+ Object value = confidentialValue.get();
return ctx.serialize(value);
}
}
diff --git a/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonSerializer.java b/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonSerializer.java
index 18beeb1f7..e90d08d0c 100644
--- a/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonSerializer.java
+++ b/extensions/gson/src/main/java/io/jsonwebtoken/gson/io/GsonSerializer.java
@@ -22,7 +22,7 @@
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.lang.Assert;
import io.jsonwebtoken.lang.Objects;
-import io.jsonwebtoken.lang.Supplier;
+import io.jsonwebtoken.security.ConfidentialValue;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@@ -34,7 +34,7 @@ public class GsonSerializer extends AbstractSerializer {
static final Gson DEFAULT_GSON = new GsonBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
- .registerTypeHierarchyAdapter(Supplier.class, GsonSupplierSerializer.INSTANCE)
+ .registerTypeHierarchyAdapter(ConfidentialValue.class, GsonConfidentialValueSerializer.INSTANCE)
.disableHtmlEscaping().create();
protected final Gson gson;
@@ -48,13 +48,13 @@ public GsonSerializer(Gson gson) {
this.gson = gson;
//ensure the necessary type adapter has been registered, and if not, throw an error:
- String json = this.gson.toJson(TestSupplier.INSTANCE);
+ String json = this.gson.toJson(TestConfidentialValue.INSTANCE);
if (json.contains("value")) {
String msg = "Invalid Gson instance - it has not been registered with the necessary " +
- Supplier.class.getName() + " type adapter. When using the GsonBuilder, ensure this " +
+ ConfidentialValue.class.getName() + " type adapter. When using the GsonBuilder, ensure this " +
"type adapter is registered by calling gsonBuilder.registerTypeHierarchyAdapter(" +
- Supplier.class.getName() + ".class, " +
- GsonSupplierSerializer.class.getName() + ".INSTANCE) before calling gsonBuilder.create()";
+ ConfidentialValue.class.getName() + ".class, " +
+ GsonConfidentialValueSerializer.class.getName() + ".INSTANCE) before calling gsonBuilder.create()";
throw new IllegalArgumentException(msg);
}
}
@@ -79,12 +79,12 @@ protected void writeValue(Object o, java.io.Writer writer) {
this.gson.toJson(o, writer);
}
- private static class TestSupplier implements Supplier {
+ private static class TestConfidentialValue implements ConfidentialValue {
- private static final TestSupplier INSTANCE = new TestSupplier<>("test");
+ private static final TestConfidentialValue INSTANCE = new TestConfidentialValue<>("test");
private final T value;
- private TestSupplier(T value) {
+ private TestConfidentialValue(T value) {
this.value = value;
}
diff --git a/extensions/gson/src/test/groovy/io/jsonwebtoken/gson/io/GsonSerializerTest.groovy b/extensions/gson/src/test/groovy/io/jsonwebtoken/gson/io/GsonSerializerTest.groovy
index 624831b77..d0b6b4b34 100644
--- a/extensions/gson/src/test/groovy/io/jsonwebtoken/gson/io/GsonSerializerTest.groovy
+++ b/extensions/gson/src/test/groovy/io/jsonwebtoken/gson/io/GsonSerializerTest.groovy
@@ -21,7 +21,7 @@ import com.google.gson.GsonBuilder
import io.jsonwebtoken.io.SerializationException
import io.jsonwebtoken.io.Serializer
import io.jsonwebtoken.lang.Strings
-import io.jsonwebtoken.lang.Supplier
+import io.jsonwebtoken.security.ConfidentialValue
import org.junit.Before
import org.junit.Test
@@ -54,7 +54,7 @@ class GsonSerializerTest {
@Test
void testGsonConstructor() {
def customGSON = new GsonBuilder()
- .registerTypeHierarchyAdapter(Supplier.class, GsonSupplierSerializer.INSTANCE)
+ .registerTypeHierarchyAdapter(ConfidentialValue.class, GsonConfidentialValueSerializer.INSTANCE)
.disableHtmlEscaping().create()
s = new GsonSerializer(customGSON)
assertSame customGSON, s.gson
@@ -83,10 +83,11 @@ class GsonSerializerTest {
fail()
} catch (IllegalArgumentException expected) {
String msg = 'Invalid Gson instance - it has not been registered with the necessary ' +
- 'io.jsonwebtoken.lang.Supplier type adapter. When using the GsonBuilder, ensure this type ' +
- 'adapter is registered by calling ' +
- 'gsonBuilder.registerTypeHierarchyAdapter(io.jsonwebtoken.lang.Supplier.class, ' +
- 'io.jsonwebtoken.gson.io.GsonSupplierSerializer.INSTANCE) before calling gsonBuilder.create()'
+ 'io.jsonwebtoken.security.ConfidentialValue type adapter. When using the GsonBuilder, ' +
+ 'ensure this type adapter is registered by calling ' +
+ 'gsonBuilder.registerTypeHierarchyAdapter(io.jsonwebtoken.security.ConfidentialValue.class, ' +
+ 'io.jsonwebtoken.gson.io.GsonConfidentialValueSerializer.INSTANCE) ' +
+ 'before calling gsonBuilder.create()'
assertEquals msg, expected.message
}
}
diff --git a/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSupplierSerializer.java b/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonConfidentialValueSerializer.java
similarity index 69%
rename from extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSupplierSerializer.java
rename to extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonConfidentialValueSerializer.java
index a415bcf09..1bfcb0013 100644
--- a/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSupplierSerializer.java
+++ b/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonConfidentialValueSerializer.java
@@ -19,21 +19,21 @@
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-import io.jsonwebtoken.lang.Supplier;
+import io.jsonwebtoken.security.ConfidentialValue;
import java.io.IOException;
-final class JacksonSupplierSerializer extends StdSerializer> {
+final class JacksonConfidentialValueSerializer extends StdSerializer> {
- static final JacksonSupplierSerializer INSTANCE = new JacksonSupplierSerializer();
+ static final JacksonConfidentialValueSerializer INSTANCE = new JacksonConfidentialValueSerializer();
- public JacksonSupplierSerializer() {
- super(Supplier.class, false);
+ public JacksonConfidentialValueSerializer() {
+ super(ConfidentialValue.class, false);
}
@Override
- public void serialize(Supplier> supplier, JsonGenerator generator, SerializerProvider provider) throws IOException {
- Object value = supplier.get();
+ public void serialize(ConfidentialValue> confidentialValue, JsonGenerator generator, SerializerProvider provider) throws IOException {
+ Object value = confidentialValue.get();
if (value == null) {
provider.defaultSerializeNull(generator);
diff --git a/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonDeserializer.java b/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonDeserializer.java
index 5736134f8..b3fe900f1 100644
--- a/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonDeserializer.java
+++ b/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonDeserializer.java
@@ -17,6 +17,7 @@
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
@@ -145,7 +146,7 @@ private static class MappedTypeDeserializer extends UntypedObjectDeserializer {
private final Map> claimTypeMap;
private MappedTypeDeserializer(Map> claimTypeMap) {
- super(null, null);
+ super((JavaType)null, null);
this.claimTypeMap = claimTypeMap;
}
diff --git a/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSerializer.java b/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSerializer.java
index a00541b61..5d8bca834 100644
--- a/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSerializer.java
+++ b/extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSerializer.java
@@ -39,7 +39,7 @@ public class JacksonSerializer extends AbstractSerializer {
static {
SimpleModule module = new SimpleModule(MODULE_ID);
- module.addSerializer(JacksonSupplierSerializer.INSTANCE);
+ module.addSerializer(JacksonConfidentialValueSerializer.INSTANCE);
MODULE = module;
}
diff --git a/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonSupplierSerializerTest.groovy b/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonConfidentialValueSerializerTest.groovy
similarity index 88%
rename from extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonSupplierSerializerTest.groovy
rename to extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonConfidentialValueSerializerTest.groovy
index 90399c95a..c923ad3ae 100644
--- a/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonSupplierSerializerTest.groovy
+++ b/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonConfidentialValueSerializerTest.groovy
@@ -15,18 +15,19 @@
*/
package io.jsonwebtoken.jackson.io
+
import io.jsonwebtoken.lang.Strings
-import io.jsonwebtoken.lang.Supplier
+import io.jsonwebtoken.security.ConfidentialValue
import org.junit.Test
import static org.junit.Assert.assertEquals
-class JacksonSupplierSerializerTest {
+class JacksonConfidentialValueSerializerTest {
@Test
void testSupplierNullValue() {
def serializer = new JacksonSerializer()
- def supplier = new Supplier() {
+ def supplier = new ConfidentialValue() {
@Override
Object get() {
return null
@@ -40,7 +41,7 @@ class JacksonSupplierSerializerTest {
@Test
void testSupplierStringValue() {
def serializer = new JacksonSerializer()
- def supplier = new Supplier() {
+ def supplier = new ConfidentialValue() {
@Override
Object get() {
return 'hello'
diff --git a/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonDeserializerTest.groovy b/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonDeserializerTest.groovy
index b21667441..aba1f921a 100644
--- a/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonDeserializerTest.groovy
+++ b/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonDeserializerTest.groovy
@@ -139,7 +139,7 @@ class JacksonDeserializerTest {
new JacksonDeserializer<>().deserialize(new StringReader(json))
fail()
} catch (DeserializationException expected) {
- String causeMsg = "Duplicate field 'bKey'\n at [Source: (StringReader); line: 5, column: 23]"
+ String causeMsg = "Duplicate field 'bKey'\n at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 5, column: 23]"
String msg = "Unable to deserialize: $causeMsg"
assertEquals msg, expected.getMessage()
assertTrue expected.getCause() instanceof JsonParseException
@@ -222,17 +222,6 @@ class JacksonDeserializerTest {
}
}
- // TODO: the following does NOT work with Java 1.7
- // when we stop supporting that version we can use a partial mock instead
- // the `typeMap.put("custom", CustomBean)` line below results in an NPE, (only on 1.7)
-
-// Map typeMap = partialMockBuilder(HashMap)
-// .addMockedMethod("containsKey")
-// .createNiceMock()
-//
-// expect(typeMap.containsKey(null)).andThrow(new NullPointerException("key is null, expected for this test"))
-// replay(typeMap)
-
typeMap.put("custom", CustomBean)
def deserializer = new JacksonDeserializer(typeMap)
diff --git a/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/TestSupplier.groovy b/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/TestConfidentialValue.groovy
similarity index 74%
rename from extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/TestSupplier.groovy
rename to extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/TestConfidentialValue.groovy
index 4faf2c8ac..08b619f52 100644
--- a/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/TestSupplier.groovy
+++ b/extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/TestConfidentialValue.groovy
@@ -15,14 +15,15 @@
*/
package io.jsonwebtoken.jackson.io
-import io.jsonwebtoken.lang.Supplier
-class TestSupplier implements Supplier {
+import io.jsonwebtoken.security.ConfidentialValue
- private static final TestSupplier INSTANCE = new TestSupplier<>("test")
+class TestConfidentialValue implements ConfidentialValue {
+
+ private static final TestConfidentialValue INSTANCE = new TestConfidentialValue<>("test")
private final T value;
- private TestSupplier(T value) {
+ private TestConfidentialValue(T value) {
this.value = value;
}
diff --git a/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java b/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java
index 0c81f5ce4..da27e5a57 100644
--- a/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java
+++ b/extensions/orgjson/src/main/java/io/jsonwebtoken/orgjson/io/OrgJsonSerializer.java
@@ -22,7 +22,7 @@
import io.jsonwebtoken.lang.DateFormats;
import io.jsonwebtoken.lang.Objects;
import io.jsonwebtoken.lang.Strings;
-import io.jsonwebtoken.lang.Supplier;
+import io.jsonwebtoken.security.ConfidentialValue;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -78,8 +78,8 @@ private Object toJSONInstance(Object object) throws IOException {
return JSONObject.NULL;
}
- if (object instanceof Supplier) {
- object = ((Supplier>) object).get();
+ if (object instanceof ConfidentialValue) {
+ object = ((ConfidentialValue>) object).get();
}
if (object instanceof JSONObject || object instanceof JSONArray
diff --git a/extensions/orgjson/src/test/groovy/io/jsonwebtoken/orgjson/io/OrgJsonSerializerTest.groovy b/extensions/orgjson/src/test/groovy/io/jsonwebtoken/orgjson/io/OrgJsonSerializerTest.groovy
index 382c5bb14..e8e5dcdf9 100644
--- a/extensions/orgjson/src/test/groovy/io/jsonwebtoken/orgjson/io/OrgJsonSerializerTest.groovy
+++ b/extensions/orgjson/src/test/groovy/io/jsonwebtoken/orgjson/io/OrgJsonSerializerTest.groovy
@@ -21,7 +21,7 @@ import io.jsonwebtoken.io.SerializationException
import io.jsonwebtoken.io.Serializer
import io.jsonwebtoken.lang.DateFormats
import io.jsonwebtoken.lang.Strings
-import io.jsonwebtoken.lang.Supplier
+import io.jsonwebtoken.security.ConfidentialValue
import org.json.JSONObject
import org.json.JSONString
import org.junit.Before
@@ -165,7 +165,7 @@ class OrgJsonSerializerTest {
@Test
void testSupplier() {
- def supplier = new Supplier() {
+ def supplier = new ConfidentialValue() {
@Override
Object get() {
return 'test'
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/CompressionCodecLocator.java b/impl/src/main/java/io/jsonwebtoken/impl/CompressionCodecLocator.java
index fe00bb545..211a60e7f 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/CompressionCodecLocator.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/CompressionCodecLocator.java
@@ -18,10 +18,11 @@
import io.jsonwebtoken.CompressionCodecResolver;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Locator;
-import io.jsonwebtoken.impl.lang.Function;
import io.jsonwebtoken.io.CompressionAlgorithm;
import io.jsonwebtoken.lang.Assert;
+import java.util.function.Function;
+
//TODO: delete when deleting CompressionCodecResolver
public class CompressionCodecLocator implements Function, Locator {
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java
index d4b63f778..11f738faa 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultClaimsBuilder.java
@@ -36,7 +36,7 @@ public Claims build() {
// @since 0.12.7 per https://github.com/jwtk/jjwt/issues/988
@SuppressWarnings("unused") // used via reflection in the api module's Jwts class.
- public static final class Supplier implements io.jsonwebtoken.lang.Supplier {
+ public static final class Supplier implements java.util.function.Supplier {
@Override
public ClaimsBuilder get() {
return new DefaultClaimsBuilder();
diff --git a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
index 27fd42d20..56706ba30 100644
--- a/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
+++ b/impl/src/main/java/io/jsonwebtoken/impl/DefaultJwtBuilder.java
@@ -29,7 +29,6 @@
import io.jsonwebtoken.impl.io.Streams;
import io.jsonwebtoken.impl.io.UncloseableInputStream;
import io.jsonwebtoken.impl.lang.Bytes;
-import io.jsonwebtoken.impl.lang.Function;
import io.jsonwebtoken.impl.lang.Functions;
import io.jsonwebtoken.impl.lang.Parameter;
import io.jsonwebtoken.impl.lang.Services;
@@ -77,6 +76,7 @@
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
public class DefaultJwtBuilder implements JwtBuilder {
@@ -239,12 +239,7 @@ public JwtBuilder signWith(K key, final SecureDigestAlgorithm
this.key = key;
//noinspection unchecked
this.sigAlg = (SecureDigestAlgorithm) alg;
- this.signFunction = Functions.wrap(new Function, byte[]>() {
- @Override
- public byte[] apply(SecureRequest request) {
- return sigAlg.digest(request);
- }
- }, SignatureException.class, "Unable to compute %s signature.", id);
+ this.signFunction = Functions.wrap(request -> sigAlg.digest(request), SignatureException.class, "Unable to compute %s signature.", id);
return this;
}
@@ -309,12 +304,7 @@ public JwtBuilder encryptWith(final K key, final KeyAlgorithm
final KeyAlgorithm alg = this.keyAlg;
final String cekMsg = "Unable to obtain content encryption key from key management algorithm '%s'.";
- this.keyAlgFunction = Functions.wrap(new Function, KeyResult>() {
- @Override
- public KeyResult apply(KeyRequest request) {
- return alg.getEncryptionKey(request);
- }
- }, SecurityException.class, cekMsg, algId);
+ this.keyAlgFunction = Functions.wrap(alg::getEncryptionKey, SecurityException.class, cekMsg, algId);
return this;
}
@@ -434,7 +424,7 @@ public JwtBuilder setAudience(String aud) {
@Override
public AudienceCollection audience() {
- return new DelegateAudienceCollection<>((JwtBuilder) this, claims().audience());
+ return new DelegateAudienceCollection<>(this, claims().audience());
}
@Override
@@ -668,12 +658,9 @@ private String unprotected(final Payload content) {
}
private void encrypt(final AeadRequest req, final AeadResult res) throws SecurityException {
- Function