mirror of https://github.com/jwtk/jjwt.git
- Ensures that Jackson duplicate property detection/rejection is enabled by default. (#895)
Fixes #877
This commit is contained in:
parent
d878404434
commit
86e06559bc
|
@ -72,14 +72,8 @@ public class JacksonDeserializer<T> extends AbstractDeserializer<T> {
|
|||
* @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);
|
||||
// DO NOT specify JacksonSerializer.DEFAULT_OBJECT_MAPPER here as that would modify the shared instance
|
||||
this(JacksonSerializer.newObjectMapper(), claimTypeMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,6 +86,46 @@ public class JacksonDeserializer<T> extends AbstractDeserializer<T> {
|
|||
this(objectMapper, (Class<T>) Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JacksonDeserializer where the values of the claims can be parsed into given types by registering
|
||||
* a type-converting {@link com.fasterxml.jackson.databind.Module Module} on the specified {@link ObjectMapper}.
|
||||
* A common usage example is to parse custom User object out of a claim, for example the claims:
|
||||
* <pre>{@code
|
||||
* {
|
||||
* "issuer": "https://issuer.example.com",
|
||||
* "user": {
|
||||
* "firstName": "Jill",
|
||||
* "lastName": "Coder"
|
||||
* }
|
||||
* }}</pre>
|
||||
* Passing a map of {@code ["user": User.class]} to this constructor would result in the {@code user} claim being
|
||||
* transformed to an instance of your custom {@code User} class, instead of the default of {@code Map}.
|
||||
* <p>
|
||||
* Because custom type parsing requires modifying the state of a Jackson {@code ObjectMapper}, this
|
||||
* constructor modifies the specified {@code objectMapper} argument and customizes it to support the
|
||||
* specified {@code claimTypeMap}.
|
||||
* <p>
|
||||
* If you do not want your {@code ObjectMapper} instance modified, but also want to support custom types for
|
||||
* JWT {@code Claims}, you will need to first customize your {@code ObjectMapper} instance by registering
|
||||
* your custom types separately and then use the {@link #JacksonDeserializer(ObjectMapper)} constructor instead
|
||||
* (which does not modify the {@code objectMapper} argument).
|
||||
*
|
||||
* @param objectMapper the objectMapper to modify by registering a custom type-converting
|
||||
* {@link com.fasterxml.jackson.databind.Module Module}
|
||||
* @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type
|
||||
* @since 0.12.4
|
||||
*/
|
||||
//TODO: Make this public on a minor release
|
||||
// (cannot do that on a point release as that would violate semver)
|
||||
private JacksonDeserializer(ObjectMapper objectMapper, Map<String, Class<?>> claimTypeMap) {
|
||||
this(objectMapper);
|
||||
Assert.notNull(claimTypeMap, "Claim type map cannot be null.");
|
||||
// register a new Deserializer on the ObjectMapper instance:
|
||||
SimpleModule module = new SimpleModule();
|
||||
module.addDeserializer(Object.class, new MappedTypeDeserializer(Collections.unmodifiableMap(claimTypeMap)));
|
||||
objectMapper.registerModule(module);
|
||||
}
|
||||
|
||||
private JacksonDeserializer(ObjectMapper objectMapper, Class<T> returnType) {
|
||||
Assert.notNull(objectMapper, "ObjectMapper cannot be null.");
|
||||
Assert.notNull(returnType, "Return type cannot be null.");
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package io.jsonwebtoken.jackson.io;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
|
@ -41,7 +42,22 @@ public class JacksonSerializer<T> extends AbstractSerializer<T> {
|
|||
MODULE = module;
|
||||
}
|
||||
|
||||
static final ObjectMapper DEFAULT_OBJECT_MAPPER = new ObjectMapper().registerModule(MODULE);
|
||||
static final ObjectMapper DEFAULT_OBJECT_MAPPER = newObjectMapper();
|
||||
|
||||
/**
|
||||
* Creates and returns a new ObjectMapper with the {@code jjwt-jackson} module registered and
|
||||
* {@code JsonParser.Feature.STRICT_DUPLICATE_DETECTION} enabled (set to true).
|
||||
*
|
||||
* @return and returns a new ObjectMapper with the {@code jjwt-jackson} module registered and
|
||||
* {@code JsonParser.Feature.STRICT_DUPLICATE_DETECTION} enabled (set to true).
|
||||
* @since 0.12.4
|
||||
*/
|
||||
// package protected on purpose, do not expose to the public API
|
||||
static ObjectMapper newObjectMapper() {
|
||||
return new ObjectMapper()
|
||||
.registerModule(MODULE)
|
||||
.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); // https://github.com/jwtk/jjwt/issues/877
|
||||
}
|
||||
|
||||
protected final ObjectMapper objectMapper;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
//file:noinspection GrDeprecatedAPIUsage
|
||||
package io.jsonwebtoken.jackson.io
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import io.jsonwebtoken.io.DeserializationException
|
||||
import io.jsonwebtoken.io.Deserializer
|
||||
|
@ -120,6 +121,31 @@ class JacksonDeserializerTest {
|
|||
assertEquals expected, result
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts https://github.com/jwtk/jjwt/issues/877
|
||||
*/
|
||||
@Test
|
||||
void testStrictDuplicateDetection() {
|
||||
// 'bKey' is repeated twice:
|
||||
String json = """
|
||||
{
|
||||
"aKey":"oneValue",
|
||||
"bKey": 15,
|
||||
"bKey": "hello"
|
||||
}
|
||||
"""
|
||||
try {
|
||||
new JacksonDeserializer<>().deserialize(new StringReader(json))
|
||||
fail()
|
||||
} catch (DeserializationException expected) {
|
||||
String causeMsg = "Duplicate field 'bKey'\n at [Source: (StringReader); line: 5, column: 23]"
|
||||
String msg = "Unable to deserialize: $causeMsg"
|
||||
assertEquals msg, expected.getMessage()
|
||||
assertTrue expected.getCause() instanceof JsonParseException
|
||||
assertEquals causeMsg, expected.getCause().getMessage()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For: https://github.com/jwtk/jjwt/issues/564
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue