Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates Jackson usage to use immutable ObjectReader/Writer instead of ObjectMapper #673

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
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.
* 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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.fasterxml.jackson.databind.DeserializationContext;
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.module.SimpleModule;
import io.jsonwebtoken.io.DeserializationException;
Expand All @@ -35,7 +36,7 @@
public class JacksonDeserializer<T> implements Deserializer<T> {

private final Class<T> returnType;
private final ObjectMapper objectMapper;
private final ObjectReader objectReader;

@SuppressWarnings("unused") //used via reflection by RuntimeClasspathDeserializerLocator
public JacksonDeserializer() {
Expand Down Expand Up @@ -68,14 +69,7 @@ public JacksonDeserializer() {
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
*/
public JacksonDeserializer(Map<String, Class> claimTypeMap) {
// DO NOT reuse JacksonSerializer.DEFAULT_OBJECT_MAPPER as this could result in sharing the custom deserializer
// 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);
this(objectMapperWithMappedTypes(claimTypeMap));
}

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

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

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;
}

/**
Expand All @@ -122,7 +128,7 @@ public Object deserialize(JsonParser parser, DeserializationContext context) thr
// check if the current claim key is mapped, if so traverse it's value
String name = parser.currentName();
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);
}
// otherwise default to super
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import io.jsonwebtoken.io.SerializationException;
import io.jsonwebtoken.io.Serializer;
import io.jsonwebtoken.lang.Assert;
Expand All @@ -28,7 +29,7 @@ public class JacksonSerializer<T> implements Serializer<T> {

static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper();

private final ObjectMapper objectMapper;
private final ObjectWriter objectWriter;

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

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

@SuppressWarnings("WeakerAccess") //for testing
protected byte[] writeValueAsBytes(T t) throws JsonProcessingException {
return this.objectMapper.writeValueAsBytes(t);
return this.objectWriter.writeValueAsBytes(t);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ class JacksonDeserializerTest {
@Test
void testDefaultConstructor() {
def deserializer = new JacksonDeserializer()
assertNotNull deserializer.objectMapper
assertNotNull deserializer.objectReader
}

@Test
void testObjectMapperConstructor() {
def customOM = new ObjectMapper()
def deserializer = new JacksonDeserializer(customOM)
assertSame customOM, deserializer.objectMapper
assertSame customOM.getDeserializationConfig(), deserializer.objectReader.config
}

@Test(expected = IllegalArgumentException)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ class JacksonSerializerTest {
@Test
void testDefaultConstructor() {
def serializer = new JacksonSerializer()
assertNotNull serializer.objectMapper
assertNotNull serializer.objectWriter
}

@Test
void testObjectMapperConstructor() {
def customOM = new ObjectMapper()
def serializer = new JacksonSerializer<>(customOM)
assertSame customOM, serializer.objectMapper
assertSame customOM.getSerializationConfig(), serializer.objectWriter.config
}

@Test(expected = IllegalArgumentException)
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<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>
<gson.version>2.8.5</gson.version>

Expand Down