mirror of https://github.com/jwtk/jjwt.git
Updates Jackson usage to use immutable ObjectReader/Writer instead of ObjectMapper
Jackson 2.10+ recommend using `ObjectReader` and `ObjectWriter` as opposed to `ObjectMapper` https://cowtowncoder.medium.com/jackson-3-0-immutability-w-builders-d9c532860d88
This commit is contained in:
parent
9007ae7c98
commit
0c55bfce67
|
@ -5,7 +5,8 @@
|
||||||
This patch release:
|
This patch release:
|
||||||
|
|
||||||
* Adds additional handling for rare JSON parsing exceptions and wraps them in a `JwtException` to allow the application to handle these conditions as JWT concerns.
|
* Adds additional handling for rare JSON parsing exceptions and wraps them in a `JwtException` to allow the application to handle these conditions as JWT concerns.
|
||||||
* Upgrades the `jjwt-jackson` module's Jackson dependency to `2.9.10.7`.
|
* Upgrades the `jjwt-jackson` module's Jackson dependency to `2.12.4`.
|
||||||
|
* Updates Jackson usage (in `jjwt-jackson`) to use immutable classes instead of using `ObjectMapper` directly.
|
||||||
|
|
||||||
### 0.11.2
|
### 0.11.2
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectReader;
|
||||||
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
|
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
|
||||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import io.jsonwebtoken.io.DeserializationException;
|
import io.jsonwebtoken.io.DeserializationException;
|
||||||
|
@ -35,7 +36,7 @@ import java.util.Map;
|
||||||
public class JacksonDeserializer<T> implements Deserializer<T> {
|
public class JacksonDeserializer<T> implements Deserializer<T> {
|
||||||
|
|
||||||
private final Class<T> returnType;
|
private final Class<T> returnType;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectReader objectReader;
|
||||||
|
|
||||||
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
|
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
|
||||||
public JacksonDeserializer() {
|
public JacksonDeserializer() {
|
||||||
|
@ -68,14 +69,7 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
|
||||||
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
|
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
|
||||||
*/
|
*/
|
||||||
public JacksonDeserializer(Map<String, Class> claimTypeMap) {
|
public JacksonDeserializer(Map<String, Class> claimTypeMap) {
|
||||||
// DO NOT reuse JacksonSerializer.DEFAULT_OBJECT_MAPPER as this could result in sharing the custom deserializer
|
this(objectMapperWithMappedTypes(claimTypeMap));
|
||||||
// between instances
|
|
||||||
this(new ObjectMapper());
|
|
||||||
Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
|
|
||||||
// register a new Deserializer
|
|
||||||
SimpleModule module = new SimpleModule();
|
|
||||||
module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
|
|
||||||
objectMapper.registerModule(module);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom ObjectMapper
|
@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom ObjectMapper
|
||||||
|
@ -86,7 +80,7 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
|
||||||
private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) {
|
private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) {
|
||||||
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
||||||
Assert.notNull(returnType, "Return type cannot be null.");
|
Assert.notNull(returnType, "Return type cannot be null.");
|
||||||
this.objectMapper = objectMapper;
|
this.objectReader = objectMapper.reader();
|
||||||
this.returnType = returnType;
|
this.returnType = returnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +95,19 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T readValue(byte[] bytes) throws IOException {
|
protected T readValue(byte[] bytes) throws IOException {
|
||||||
return objectMapper.readValue(bytes, returnType);
|
return objectReader.readValue(bytes, returnType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ObjectMapper objectMapperWithMappedTypes(Map<String, Class> claimTypeMap) {
|
||||||
|
// DO NOT reuse JacksonSerializer.DEFAULT_OBJECT_MAPPER as this could result in sharing the custom deserializer
|
||||||
|
// between instances
|
||||||
|
Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
// register a new Deserializer
|
||||||
|
SimpleModule module = new SimpleModule();
|
||||||
|
module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
|
||||||
|
objectMapper.registerModule(module);
|
||||||
|
return objectMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,7 +128,7 @@ public class JacksonDeserializer<T> implements Deserializer<T> {
|
||||||
// check if the current claim key is mapped, if so traverse it's value
|
// check if the current claim key is mapped, if so traverse it's value
|
||||||
String name = parser.currentName();
|
String name = parser.currentName();
|
||||||
if (claimTypeMap != null && name != null && claimTypeMap.containsKey(name)) {
|
if (claimTypeMap != null && name != null && claimTypeMap.containsKey(name)) {
|
||||||
Class type = claimTypeMap.get(name);
|
Class<?> type = claimTypeMap.get(name);
|
||||||
return parser.readValueAsTree().traverse(parser.getCodec()).readValueAs(type);
|
return parser.readValueAsTree().traverse(parser.getCodec()).readValueAs(type);
|
||||||
}
|
}
|
||||||
// otherwise default to super
|
// otherwise default to super
|
||||||
|
|
|
@ -17,6 +17,7 @@ package io.jsonwebtoken.jackson.io;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
import io.jsonwebtoken.io.SerializationException;
|
import io.jsonwebtoken.io.SerializationException;
|
||||||
import io.jsonwebtoken.io.Serializer;
|
import io.jsonwebtoken.io.Serializer;
|
||||||
import io.jsonwebtoken.lang.Assert;
|
import io.jsonwebtoken.lang.Assert;
|
||||||
|
@ -28,7 +29,7 @@ public class JacksonSerializer<T> implements Serializer<T> {
|
||||||
|
|
||||||
static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper();
|
static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper();
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectWriter objectWriter;
|
||||||
|
|
||||||
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
|
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
|
||||||
public JacksonSerializer() {
|
public JacksonSerializer() {
|
||||||
|
@ -38,7 +39,7 @@ public class JacksonSerializer<T> implements Serializer<T> {
|
||||||
@SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom ObjectMapper
|
@SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom ObjectMapper
|
||||||
public JacksonSerializer(ObjectMapper objectMapper) {
|
public JacksonSerializer(ObjectMapper objectMapper) {
|
||||||
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
||||||
this.objectMapper = objectMapper;
|
this.objectWriter = objectMapper.writer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -54,6 +55,6 @@ public class JacksonSerializer<T> implements Serializer<T> {
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess") //for testing
|
@SuppressWarnings("WeakerAccess") //for testing
|
||||||
protected byte[] writeValueAsBytes(T t) throws JsonProcessingException {
|
protected byte[] writeValueAsBytes(T t) throws JsonProcessingException {
|
||||||
return this.objectMapper.writeValueAsBytes(t);
|
return this.objectWriter.writeValueAsBytes(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,14 @@ class JacksonDeserializerTest {
|
||||||
@Test
|
@Test
|
||||||
void testDefaultConstructor() {
|
void testDefaultConstructor() {
|
||||||
def deserializer = new JacksonDeserializer()
|
def deserializer = new JacksonDeserializer()
|
||||||
assertNotNull deserializer.objectMapper
|
assertNotNull deserializer.objectReader
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testObjectMapperConstructor() {
|
void testObjectMapperConstructor() {
|
||||||
def customOM = new ObjectMapper()
|
def customOM = new ObjectMapper()
|
||||||
def deserializer = new JacksonDeserializer(customOM)
|
def deserializer = new JacksonDeserializer(customOM)
|
||||||
assertSame customOM, deserializer.objectMapper
|
assertSame customOM.getDeserializationConfig(), deserializer.objectReader.config
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException)
|
@Test(expected = IllegalArgumentException)
|
||||||
|
|
|
@ -37,14 +37,14 @@ class JacksonSerializerTest {
|
||||||
@Test
|
@Test
|
||||||
void testDefaultConstructor() {
|
void testDefaultConstructor() {
|
||||||
def serializer = new JacksonSerializer()
|
def serializer = new JacksonSerializer()
|
||||||
assertNotNull serializer.objectMapper
|
assertNotNull serializer.objectWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testObjectMapperConstructor() {
|
void testObjectMapperConstructor() {
|
||||||
def customOM = new ObjectMapper()
|
def customOM = new ObjectMapper()
|
||||||
def serializer = new JacksonSerializer<>(customOM)
|
def serializer = new JacksonSerializer<>(customOM)
|
||||||
assertSame customOM, serializer.objectMapper
|
assertSame customOM.getSerializationConfig(), serializer.objectWriter.config
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException)
|
@Test(expected = IllegalArgumentException)
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -74,7 +74,7 @@
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<buildNumber>${user.name}-${maven.build.timestamp}</buildNumber>
|
<buildNumber>${user.name}-${maven.build.timestamp}</buildNumber>
|
||||||
|
|
||||||
<jackson.version>2.9.10.7</jackson.version>
|
<jackson.version>2.12.4</jackson.version>
|
||||||
<orgjson.version>20180130</orgjson.version>
|
<orgjson.version>20180130</orgjson.version>
|
||||||
<gson.version>2.8.5</gson.version>
|
<gson.version>2.8.5</gson.version>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue