mirror of https://github.com/jwtk/jjwt.git
Merge pull request #414 from patton73/master
Added Gson serialization/deserialization Extension
This commit is contained in:
commit
ff8a6bfe58
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright 2018 JWTK
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-root</artifactId>
|
||||||
|
<version>0.10.8-SNAPSHOT</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>jjwt-gson</artifactId>
|
||||||
|
<name>JJWT :: Extensions :: Gson</name>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<jjwt.root>${basedir}/../..</jjwt.root>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,44 @@
|
||||||
|
package io.jsonwebtoken.gson.io;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import io.jsonwebtoken.io.DeserializationException;
|
||||||
|
import io.jsonwebtoken.io.Deserializer;
|
||||||
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GsonDeserializer<T> implements Deserializer<T> {
|
||||||
|
|
||||||
|
private final Class<T> returnType;
|
||||||
|
private final Gson gson;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
|
||||||
|
public GsonDeserializer() {
|
||||||
|
this(GsonSerializer.DEFAULT_GSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom gson
|
||||||
|
public GsonDeserializer(Gson gson) {
|
||||||
|
this(gson, (Class<T>) Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private GsonDeserializer(Gson gson, Class<T> returnType) {
|
||||||
|
Assert.notNull(gson, "gson cannot be null.");
|
||||||
|
Assert.notNull(returnType, "Return type cannot be null.");
|
||||||
|
this.gson = gson;
|
||||||
|
this.returnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T deserialize(byte[] bytes) throws DeserializationException {
|
||||||
|
try {
|
||||||
|
return readValue(bytes);
|
||||||
|
} catch (IOException e) {
|
||||||
|
String msg = "Unable to deserialize bytes into a " + returnType.getName() + " instance: " + e.getMessage();
|
||||||
|
throw new DeserializationException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected T readValue(byte[] bytes) throws IOException {
|
||||||
|
return gson.fromJson(new String(bytes), returnType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package io.jsonwebtoken.gson.io;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import io.jsonwebtoken.io.Encoders;
|
||||||
|
import io.jsonwebtoken.io.SerializationException;
|
||||||
|
import io.jsonwebtoken.io.Serializer;
|
||||||
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
import io.jsonwebtoken.lang.Strings;
|
||||||
|
|
||||||
|
public class GsonSerializer<T> implements Serializer<T> {
|
||||||
|
|
||||||
|
static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||||
|
private Gson gson;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
|
||||||
|
public GsonSerializer() {
|
||||||
|
this(DEFAULT_GSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom gson
|
||||||
|
public GsonSerializer(Gson gson) {
|
||||||
|
Assert.notNull(gson, "gson cannot be null.");
|
||||||
|
this.gson = gson;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] serialize(T t) throws SerializationException {
|
||||||
|
Assert.notNull(t, "Object to serialize cannot be null.");
|
||||||
|
try {
|
||||||
|
return writeValueAsBytes(t);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = "Unable to serialize object: " + e.getMessage();
|
||||||
|
throw new SerializationException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess") //for testing
|
||||||
|
protected byte[] writeValueAsBytes(T t) {
|
||||||
|
Object o;
|
||||||
|
if (t instanceof byte[]) {
|
||||||
|
o = Encoders.BASE64.encode((byte[]) t);
|
||||||
|
} else if (t instanceof char[]) {
|
||||||
|
o = new String((char[]) t);
|
||||||
|
} else {
|
||||||
|
o = t;
|
||||||
|
}
|
||||||
|
return this.gson.toJson(o).getBytes(Strings.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package io.jsonwebtoken.gson.io
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import io.jsonwebtoken.io.DeserializationException
|
||||||
|
import io.jsonwebtoken.lang.Strings
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.*
|
||||||
|
import static org.junit.Assert.*
|
||||||
|
|
||||||
|
class GsonDeserializerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDefaultConstructor() {
|
||||||
|
def deserializer = new GsonDeserializer()
|
||||||
|
assertNotNull deserializer.gson
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testObjectMapperConstructor() {
|
||||||
|
def customGSON = new Gson()
|
||||||
|
def deserializer = new GsonDeserializer(customGSON)
|
||||||
|
assertSame customGSON, deserializer.gson
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException)
|
||||||
|
void testObjectMapperConstructorWithNullArgument() {
|
||||||
|
new GsonDeserializer<>(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeserialize() {
|
||||||
|
byte[] serialized = '{"hello":"世界"}'.getBytes(Strings.UTF_8)
|
||||||
|
def expected = [hello: '世界']
|
||||||
|
def result = new GsonDeserializer().deserialize(serialized)
|
||||||
|
assertEquals expected, result
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDeserializeFailsWithJsonProcessingException() {
|
||||||
|
|
||||||
|
def ex = createMock(java.io.IOException)
|
||||||
|
|
||||||
|
expect(ex.getMessage()).andReturn('foo')
|
||||||
|
|
||||||
|
def deserializer = new GsonDeserializer() {
|
||||||
|
@Override
|
||||||
|
protected Object readValue(byte[] bytes) throws java.io.IOException {
|
||||||
|
throw ex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
replay ex
|
||||||
|
|
||||||
|
try {
|
||||||
|
deserializer.deserialize('{"hello":"世界"}'.getBytes(Strings.UTF_8))
|
||||||
|
fail()
|
||||||
|
} catch (DeserializationException se) {
|
||||||
|
assertEquals 'Unable to deserialize bytes into a java.lang.Object instance: foo', se.getMessage()
|
||||||
|
assertSame ex, se.getCause()
|
||||||
|
}
|
||||||
|
|
||||||
|
verify ex
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
package io.jsonwebtoken.gson.io
|
||||||
|
|
||||||
|
import io.jsonwebtoken.lang.Strings
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.easymock.EasyMock.*
|
||||||
|
import static org.junit.Assert.*
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import io.jsonwebtoken.io.SerializationException
|
||||||
|
|
||||||
|
class GsonSerializerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDefaultConstructor() {
|
||||||
|
def serializer = new GsonSerializer()
|
||||||
|
assertNotNull serializer.gson
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testObjectMapperConstructor() {
|
||||||
|
def customGSON = new Gson()
|
||||||
|
def serializer = new GsonSerializer<>(customGSON)
|
||||||
|
assertSame customGSON, serializer.gson
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException)
|
||||||
|
void testObjectMapperConstructorWithNullArgument() {
|
||||||
|
new GsonSerializer<>(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testByte() {
|
||||||
|
byte[] expected = "120".getBytes(Strings.UTF_8) //ascii("x") = 120
|
||||||
|
byte[] bytes = "x".getBytes(Strings.UTF_8)
|
||||||
|
byte[] result = new GsonSerializer().serialize(bytes[0]) //single byte
|
||||||
|
assertTrue Arrays.equals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testByteArray() { //expect Base64 string by default:
|
||||||
|
byte[] bytes = "hi".getBytes(Strings.UTF_8)
|
||||||
|
String expected = '"aGk="' as String //base64(hi) --> aGk=
|
||||||
|
byte[] result = new GsonSerializer().serialize(bytes)
|
||||||
|
assertEquals expected, new String(result, Strings.UTF_8)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEmptyByteArray() { //expect Base64 string by default:
|
||||||
|
byte[] bytes = new byte[0]
|
||||||
|
byte[] result = new GsonSerializer().serialize(bytes)
|
||||||
|
assertEquals '""', new String(result, Strings.UTF_8)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testChar() { //expect Base64 string by default:
|
||||||
|
byte[] result = new GsonSerializer().serialize('h' as char)
|
||||||
|
assertEquals "\"h\"", new String(result, Strings.UTF_8)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCharArray() { //expect Base64 string by default:
|
||||||
|
byte[] result = new GsonSerializer().serialize("hi".toCharArray())
|
||||||
|
assertEquals "\"hi\"", new String(result, Strings.UTF_8)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSerialize() {
|
||||||
|
byte[] expected = '{"hello":"世界"}'.getBytes(Strings.UTF_8)
|
||||||
|
byte[] result = new GsonSerializer().serialize([hello: '世界'])
|
||||||
|
assertTrue Arrays.equals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSerializeFailsWithJsonProcessingException() {
|
||||||
|
|
||||||
|
def ex = createMock(SerializationException)
|
||||||
|
|
||||||
|
expect(ex.getMessage()).andReturn('foo')
|
||||||
|
|
||||||
|
def serializer = new GsonSerializer() {
|
||||||
|
@Override
|
||||||
|
protected byte[] writeValueAsBytes(Object o) throws SerializationException {
|
||||||
|
throw ex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
replay ex
|
||||||
|
|
||||||
|
try {
|
||||||
|
serializer.serialize([hello: 'world'])
|
||||||
|
fail()
|
||||||
|
} catch (SerializationException se) {
|
||||||
|
assertEquals 'Unable to serialize object: foo', se.getMessage()
|
||||||
|
assertSame ex, se.getCause()
|
||||||
|
}
|
||||||
|
|
||||||
|
verify ex
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,7 @@
|
||||||
<modules>
|
<modules>
|
||||||
<module>jackson</module>
|
<module>jackson</module>
|
||||||
<module>orgjson</module>
|
<module>orgjson</module>
|
||||||
|
<module>gson</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -54,6 +54,11 @@
|
||||||
<artifactId>jjwt-orgjson</artifactId>
|
<artifactId>jjwt-orgjson</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-gson</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
|
@ -34,6 +34,8 @@ public class RuntimeClasspathDeserializerLocator<T> implements InstanceLocator<D
|
||||||
return Classes.newInstance("io.jsonwebtoken.io.JacksonDeserializer");
|
return Classes.newInstance("io.jsonwebtoken.io.JacksonDeserializer");
|
||||||
} else if (isAvailable("io.jsonwebtoken.io.OrgJsonDeserializer")) {
|
} else if (isAvailable("io.jsonwebtoken.io.OrgJsonDeserializer")) {
|
||||||
return Classes.newInstance("io.jsonwebtoken.io.OrgJsonDeserializer");
|
return Classes.newInstance("io.jsonwebtoken.io.OrgJsonDeserializer");
|
||||||
|
} else if (isAvailable("io.jsonwebtoken.gson.io.GsonDeserializer")) {
|
||||||
|
return Classes.newInstance("io.jsonwebtoken.gson.io.GsonDeserializer");
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unable to discover any JSON Deserializer implementations on the classpath.");
|
throw new IllegalStateException("Unable to discover any JSON Deserializer implementations on the classpath.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,8 @@ public class RuntimeClasspathSerializerLocator implements InstanceLocator<Serial
|
||||||
return Classes.newInstance("io.jsonwebtoken.io.JacksonSerializer");
|
return Classes.newInstance("io.jsonwebtoken.io.JacksonSerializer");
|
||||||
} else if (isAvailable("io.jsonwebtoken.io.OrgJsonSerializer")) {
|
} else if (isAvailable("io.jsonwebtoken.io.OrgJsonSerializer")) {
|
||||||
return Classes.newInstance("io.jsonwebtoken.io.OrgJsonSerializer");
|
return Classes.newInstance("io.jsonwebtoken.io.OrgJsonSerializer");
|
||||||
|
} else if (isAvailable("io.jsonwebtoken.gson.io.GsonSerializer")) {
|
||||||
|
return Classes.newInstance("io.jsonwebtoken.gson.io.GsonSerializer");
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Unable to discover any JSON Serializer implementations on the classpath.");
|
throw new IllegalStateException("Unable to discover any JSON Serializer implementations on the classpath.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import io.jsonwebtoken.io.Deserializer
|
import io.jsonwebtoken.io.Deserializer
|
||||||
import io.jsonwebtoken.io.JacksonDeserializer
|
import io.jsonwebtoken.io.JacksonDeserializer
|
||||||
import io.jsonwebtoken.io.OrgJsonDeserializer
|
import io.jsonwebtoken.io.OrgJsonDeserializer
|
||||||
|
import io.jsonwebtoken.gson.io.GsonDeserializer
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -96,4 +97,23 @@ class RuntimeClasspathDeserializerLocatorTest {
|
||||||
def deserializer = locator.getInstance()
|
def deserializer = locator.getInstance()
|
||||||
assertTrue deserializer instanceof OrgJsonDeserializer
|
assertTrue deserializer instanceof OrgJsonDeserializer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGson() {
|
||||||
|
def locator = new RuntimeClasspathDeserializerLocator() {
|
||||||
|
@Override
|
||||||
|
protected boolean isAvailable(String fqcn) {
|
||||||
|
if (JacksonDeserializer.class.getName().equals(fqcn)) {
|
||||||
|
return false; //skip it to allow the Gson impl to be created
|
||||||
|
}
|
||||||
|
if (OrgJsonDeserializer.class.getName().equals(fqcn)) {
|
||||||
|
return false; //skip it to allow the Gson impl to be created
|
||||||
|
}
|
||||||
|
return super.isAvailable(fqcn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def deserializer = locator.getInstance()
|
||||||
|
assertTrue deserializer instanceof GsonDeserializer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package io.jsonwebtoken.impl.io
|
||||||
import io.jsonwebtoken.io.Serializer
|
import io.jsonwebtoken.io.Serializer
|
||||||
import io.jsonwebtoken.io.JacksonSerializer
|
import io.jsonwebtoken.io.JacksonSerializer
|
||||||
import io.jsonwebtoken.io.OrgJsonSerializer
|
import io.jsonwebtoken.io.OrgJsonSerializer
|
||||||
|
import io.jsonwebtoken.gson.io.GsonSerializer
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -95,4 +96,23 @@ class RuntimeClasspathSerializerLocatorTest {
|
||||||
def serializer = locator.getInstance()
|
def serializer = locator.getInstance()
|
||||||
assertTrue serializer instanceof OrgJsonSerializer
|
assertTrue serializer instanceof OrgJsonSerializer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGson() {
|
||||||
|
def locator = new RuntimeClasspathSerializerLocator() {
|
||||||
|
@Override
|
||||||
|
protected boolean isAvailable(String fqcn) {
|
||||||
|
if (JacksonSerializer.class.getName().equals(fqcn)) {
|
||||||
|
return false //skip it to allow the Gson impl to be created
|
||||||
|
}
|
||||||
|
if (OrgJsonSerializer.class.getName().equals(fqcn)) {
|
||||||
|
return false //skip it to allow the Gson impl to be created
|
||||||
|
}
|
||||||
|
return super.isAvailable(fqcn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def serializer = locator.getInstance()
|
||||||
|
assertTrue serializer instanceof GsonSerializer
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
11
pom.xml
11
pom.xml
|
@ -90,6 +90,7 @@
|
||||||
|
|
||||||
<jackson.version>2.9.9.1</jackson.version>
|
<jackson.version>2.9.9.1</jackson.version>
|
||||||
<orgjson.version>20180130</orgjson.version>
|
<orgjson.version>20180130</orgjson.version>
|
||||||
|
<gson.version>2.8.5</gson.version>
|
||||||
|
|
||||||
<!-- Optional Runtime Dependencies: -->
|
<!-- Optional Runtime Dependencies: -->
|
||||||
<bouncycastle.version>1.60</bouncycastle.version>
|
<bouncycastle.version>1.60</bouncycastle.version>
|
||||||
|
@ -131,6 +132,11 @@
|
||||||
<artifactId>jjwt-orgjson</artifactId>
|
<artifactId>jjwt-orgjson</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
|
<artifactId>jjwt-gson</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
<artifactId>jackson-databind</artifactId>
|
<artifactId>jackson-databind</artifactId>
|
||||||
|
@ -141,6 +147,11 @@
|
||||||
<artifactId>json</artifactId>
|
<artifactId>json</artifactId>
|
||||||
<version>${orgjson.version}</version>
|
<version>${orgjson.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>${gson.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Used only during testing for PS256, PS384 and PS512 since JDK <= 10 doesn't support them: -->
|
<!-- Used only during testing for PS256, PS384 and PS512 since JDK <= 10 doesn't support them: -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
Loading…
Reference in New Issue