Skip to content

Commit 0c55bfc

Browse files
committed
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
1 parent 9007ae7 commit 0c55bfc

File tree

6 files changed

+29
-21
lines changed

6 files changed

+29
-21
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
This patch release:
66

77
* 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.
8-
* Upgrades the `jjwt-jackson` module's Jackson dependency to `2.9.10.7`.
8+
* Upgrades the `jjwt-jackson` module's Jackson dependency to `2.12.4`.
9+
* Updates Jackson usage (in `jjwt-jackson`) to use immutable classes instead of using `ObjectMapper` directly.
910

1011
### 0.11.2
1112

extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonDeserializer.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.fasterxml.jackson.databind.DeserializationContext;
2020
import com.fasterxml.jackson.databind.ObjectMapper;
2121

22+
import com.fasterxml.jackson.databind.ObjectReader;
2223
import com.fasterxml.jackson.databind.deser.std.UntypedObjectDeserializer;
2324
import com.fasterxml.jackson.databind.module.SimpleModule;
2425
import io.jsonwebtoken.io.DeserializationException;
@@ -35,7 +36,7 @@
3536
public class JacksonDeserializer<T> implements Deserializer<T> {
3637

3738
private final Class<T> returnType;
38-
private final ObjectMapper objectMapper;
39+
private final ObjectReader objectReader;
3940

4041
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
4142
public JacksonDeserializer() {
@@ -68,14 +69,7 @@ public JacksonDeserializer() {
6869
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
6970
*/
7071
public JacksonDeserializer(Map<String, Class> claimTypeMap) {
71-
// DO NOT reuse JacksonSerializer.DEFAULT_OBJECT_MAPPER as this could result in sharing the custom deserializer
72-
// between instances
73-
this(new ObjectMapper());
74-
Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
75-
// register a new Deserializer
76-
SimpleModule module = new SimpleModule();
77-
module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
78-
objectMapper.registerModule(module);
72+
this(objectMapperWithMappedTypes(claimTypeMap));
7973
}
8074

8175
@SuppressWarnings({"unchecked", "WeakerAccess", "unused"}) // for end-users providing a custom ObjectMapper
@@ -86,7 +80,7 @@ public JacksonDeserializer(ObjectMapper objectMapper) {
8680
private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) {
8781
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
8882
Assert.notNull(returnType, "Return type cannot be null.");
89-
this.objectMapper = objectMapper;
83+
this.objectReader = objectMapper.reader();
9084
this.returnType = returnType;
9185
}
9286

@@ -101,7 +95,19 @@ public T deserialize(byte[] bytes) throws DeserializationException {
10195
}
10296

10397
protected T readValue(byte[] bytes) throws IOException {
104-
return objectMapper.readValue(bytes, returnType);
98+
return objectReader.readValue(bytes, returnType);
99+
}
100+
101+
private static ObjectMapper objectMapperWithMappedTypes(Map<String, Class> claimTypeMap) {
102+
// DO NOT reuse JacksonSerializer.DEFAULT_OBJECT_MAPPER as this could result in sharing the custom deserializer
103+
// between instances
104+
Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
105+
ObjectMapper objectMapper = new ObjectMapper();
106+
// register a new Deserializer
107+
SimpleModule module = new SimpleModule();
108+
module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
109+
objectMapper.registerModule(module);
110+
return objectMapper;
105111
}
106112

107113
/**
@@ -122,7 +128,7 @@ public Object deserialize(JsonParser parser, DeserializationContext context) thr
122128
// check if the current claim key is mapped, if so traverse it's value
123129
String name = parser.currentName();
124130
if (claimTypeMap != null && name != null && claimTypeMap.containsKey(name)) {
125-
Class type = claimTypeMap.get(name);
131+
Class<?> type = claimTypeMap.get(name);
126132
return parser.readValueAsTree().traverse(parser.getCodec()).readValueAs(type);
127133
}
128134
// otherwise default to super

extensions/jackson/src/main/java/io/jsonwebtoken/jackson/io/JacksonSerializer.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.fasterxml.jackson.core.JsonProcessingException;
1919
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.fasterxml.jackson.databind.ObjectWriter;
2021
import io.jsonwebtoken.io.SerializationException;
2122
import io.jsonwebtoken.io.Serializer;
2223
import io.jsonwebtoken.lang.Assert;
@@ -28,7 +29,7 @@ public class JacksonSerializer<T> implements Serializer<T> {
2829

2930
static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper();
3031

31-
private final ObjectMapper objectMapper;
32+
private final ObjectWriter objectWriter;
3233

3334
@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
3435
public JacksonSerializer() {
@@ -38,7 +39,7 @@ public JacksonSerializer() {
3839
@SuppressWarnings("WeakerAccess") //intended for end-users to use when providing a custom ObjectMapper
3940
public JacksonSerializer(ObjectMapper objectMapper) {
4041
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
41-
this.objectMapper = objectMapper;
42+
this.objectWriter = objectMapper.writer();
4243
}
4344

4445
@Override
@@ -54,6 +55,6 @@ public byte[] serialize(T t) throws SerializationException {
5455

5556
@SuppressWarnings("WeakerAccess") //for testing
5657
protected byte[] writeValueAsBytes(T t) throws JsonProcessingException {
57-
return this.objectMapper.writeValueAsBytes(t);
58+
return this.objectWriter.writeValueAsBytes(t);
5859
}
5960
}

extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonDeserializerTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ class JacksonDeserializerTest {
3838
@Test
3939
void testDefaultConstructor() {
4040
def deserializer = new JacksonDeserializer()
41-
assertNotNull deserializer.objectMapper
41+
assertNotNull deserializer.objectReader
4242
}
4343

4444
@Test
4545
void testObjectMapperConstructor() {
4646
def customOM = new ObjectMapper()
4747
def deserializer = new JacksonDeserializer(customOM)
48-
assertSame customOM, deserializer.objectMapper
48+
assertSame customOM.getDeserializationConfig(), deserializer.objectReader.config
4949
}
5050

5151
@Test(expected = IllegalArgumentException)

extensions/jackson/src/test/groovy/io/jsonwebtoken/jackson/io/JacksonSerializerTest.groovy

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ class JacksonSerializerTest {
3737
@Test
3838
void testDefaultConstructor() {
3939
def serializer = new JacksonSerializer()
40-
assertNotNull serializer.objectMapper
40+
assertNotNull serializer.objectWriter
4141
}
4242

4343
@Test
4444
void testObjectMapperConstructor() {
4545
def customOM = new ObjectMapper()
4646
def serializer = new JacksonSerializer<>(customOM)
47-
assertSame customOM, serializer.objectMapper
47+
assertSame customOM.getSerializationConfig(), serializer.objectWriter.config
4848
}
4949

5050
@Test(expected = IllegalArgumentException)

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
7575
<buildNumber>${user.name}-${maven.build.timestamp}</buildNumber>
7676

77-
<jackson.version>2.9.10.7</jackson.version>
77+
<jackson.version>2.12.4</jackson.version>
7878
<orgjson.version>20180130</orgjson.version>
7979
<gson.version>2.8.5</gson.version>
8080

0 commit comments

Comments
 (0)