-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Added parser for Jackson3 #1032
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
base: master
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <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/xsd/maven-4.0.0.xsd"> | ||
| <modelVersion>4.0.0</modelVersion> | ||
|
|
||
| <parent> | ||
| <groupId>io.jsonwebtoken</groupId> | ||
| <artifactId>jjwt-root</artifactId> | ||
| <version>0.14.0-SNAPSHOT</version> | ||
| <relativePath>../../pom.xml</relativePath> | ||
| </parent> | ||
|
|
||
| <artifactId>jjwt-jackson3</artifactId> | ||
| <name>JJWT :: Extensions :: Jackson3</name> | ||
| <packaging>jar</packaging> | ||
|
|
||
| <properties> | ||
| <jjwt.root>${basedir}/../..</jjwt.root> | ||
| </properties> | ||
|
|
||
|
|
||
| <dependencies> | ||
| <dependency> | ||
| <groupId>io.jsonwebtoken</groupId> | ||
| <artifactId>jjwt-api</artifactId> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>tools.jackson.core</groupId> | ||
| <artifactId>jackson-databind</artifactId> | ||
| </dependency> | ||
| </dependencies> | ||
|
|
||
| <build> | ||
| <plugins> | ||
| <!-- The following plugin section is used in jjwt-jackson and jjwt-orgjson, to repackage (and verify) | ||
| binary compatibility with previous versions. In v0.11.0 the implementations changed packages to | ||
| avoid split package issues with Java 9+ see: https://github.com/jwtk/jjwt/issues/399 --> | ||
| <!-- TODO: remove these deprecated packages and this config before v1.0 --> | ||
| <plugin> | ||
| <groupId>org.apache.maven.plugins</groupId> | ||
| <artifactId>maven-shade-plugin</artifactId> | ||
| <configuration> | ||
| <relocations> | ||
| <relocation> | ||
| <pattern>io.jsonwebtoken.jackson.io</pattern> | ||
| <shadedPattern>io.jsonwebtoken.io</shadedPattern> | ||
| <includes>io.jsonwebtoken.jackson.io.*</includes> | ||
| </relocation> | ||
| </relocations> | ||
| </configuration> | ||
| </plugin> | ||
|
||
| <!--plugin> | ||
| <groupId>com.github.siom79.japicmp</groupId> | ||
| <artifactId>japicmp-maven-plugin</artifactId> | ||
| <configuration> | ||
| <parameter> | ||
| <ignoreMissingClasses>true</ignoreMissingClasses> | ||
| </parameter> | ||
| </configuration> | ||
| </plugin--> | ||
| </plugins> | ||
| </build> | ||
| </project> | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,174 @@ | ||||||
| /* | ||||||
| * Copyright (C) 2014 jsonwebtoken.io | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| * | ||||||
| * 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. | ||||||
| */ | ||||||
| package io.jsonwebtoken.jackson.io; | ||||||
|
|
||||||
| import io.jsonwebtoken.io.AbstractDeserializer; | ||||||
| import io.jsonwebtoken.lang.Assert; | ||||||
| import tools.jackson.core.JacksonException; | ||||||
| import tools.jackson.core.JsonParser; | ||||||
| import tools.jackson.databind.DeserializationContext; | ||||||
| import tools.jackson.databind.JavaType; | ||||||
| import tools.jackson.databind.JsonNode; | ||||||
| import tools.jackson.databind.ObjectMapper; | ||||||
| import tools.jackson.databind.deser.jdk.UntypedObjectDeserializer; | ||||||
| import tools.jackson.databind.module.SimpleModule; | ||||||
|
|
||||||
| import java.io.Reader; | ||||||
| import java.util.Collections; | ||||||
| import java.util.Map; | ||||||
|
|
||||||
| /** | ||||||
| * Deserializer using a Jackson {@link ObjectMapper}. | ||||||
| * | ||||||
| * @since 0.10.0 | ||||||
|
||||||
| */ | ||||||
| public class Jackson3Deserializer<T> extends AbstractDeserializer<T> { | ||||||
|
|
||||||
| private final Class<T> returnType; | ||||||
|
|
||||||
| private final ObjectMapper objectMapper; | ||||||
|
|
||||||
| /** | ||||||
| * Constructor using JJWT's default {@link ObjectMapper} singleton for deserialization. | ||||||
| */ | ||||||
| public Jackson3Deserializer() { | ||||||
| this(Jackson3Serializer.DEFAULT_OBJECT_MAPPER); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Creates a new JacksonDeserializer where the values of the claims can be parsed into given types. 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 creates a new internal {@code ObjectMapper} instance and customizes it to support the | ||||||
| * specified {@code claimTypeMap}. This ensures that the JJWT parsing behavior does not unexpectedly | ||||||
| * modify the state of another application-specific {@code ObjectMapper}. | ||||||
| * <p> | ||||||
| * If you would like to use your own {@code ObjectMapper} instance that also supports custom types for | ||||||
| * JWT {@code Claims}, you will need to first customize your {@code ObjectMapper} instance by registering | ||||||
| * your custom types and then use the {@link #Jackson3Deserializer(ObjectMapper)} constructor instead. | ||||||
| * | ||||||
| * @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type | ||||||
| */ | ||||||
| public Jackson3Deserializer(Map<String, Class<?>> claimTypeMap) { | ||||||
| // DO NOT specify JacksonSerializer.DEFAULT_OBJECT_MAPPER here as that would modify the shared instance | ||||||
| this(Jackson3Serializer.newObjectMapper(), claimTypeMap); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * Constructor using the specified Jackson {@link ObjectMapper}. | ||||||
| * | ||||||
| * @param objectMapper the ObjectMapper to use for deserialization. | ||||||
| */ | ||||||
| @SuppressWarnings("unchecked") | ||||||
| public Jackson3Deserializer(ObjectMapper objectMapper) { | ||||||
| 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 tools.jackson.databind.JacksonModule 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 #Jackson3Deserializer(ObjectMapper)} constructor instead | ||||||
| * (which does not modify the {@code objectMapper} argument). | ||||||
| * | ||||||
| * @param objectMapper the objectMapper to modify by registering a custom type-converting | ||||||
| * {@link tools.jackson.databind.JacksonModule Module} | ||||||
| * @param claimTypeMap The claim name-to-class map used to deserialize claims into the given type | ||||||
| * @since 0.13.0 | ||||||
|
||||||
| * @since 0.13.0 |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,95 @@ | ||||||||||
| /* | ||||||||||
| * Copyright (C) 2014 jsonwebtoken.io | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| * | ||||||||||
| * 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. | ||||||||||
| */ | ||||||||||
| package io.jsonwebtoken.jackson.io; | ||||||||||
|
|
||||||||||
| import io.jsonwebtoken.io.AbstractSerializer; | ||||||||||
| import io.jsonwebtoken.lang.Assert; | ||||||||||
| import tools.jackson.core.StreamReadFeature; | ||||||||||
| import tools.jackson.databind.DeserializationFeature; | ||||||||||
| import tools.jackson.databind.JacksonModule; | ||||||||||
| import tools.jackson.databind.ObjectMapper; | ||||||||||
| import tools.jackson.databind.ObjectWriter; | ||||||||||
| import tools.jackson.databind.module.SimpleModule; | ||||||||||
|
|
||||||||||
| import java.io.OutputStream; | ||||||||||
|
|
||||||||||
| import static tools.jackson.core.StreamWriteFeature.AUTO_CLOSE_TARGET; | ||||||||||
| import static tools.jackson.databind.json.JsonMapper.builder; | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Serializer using a Jackson {@link ObjectMapper}. | ||||||||||
| * | ||||||||||
| * @since 0.10.0 | ||||||||||
|
||||||||||
| */ | ||||||||||
| public class Jackson3Serializer<T> extends AbstractSerializer<T> { | ||||||||||
|
|
||||||||||
| static final String MODULE_ID = "jjwt-jackson"; | ||||||||||
|
||||||||||
| static final JacksonModule MODULE; | ||||||||||
|
|
||||||||||
| static { | ||||||||||
| SimpleModule module = new SimpleModule(MODULE_ID); | ||||||||||
| module.addSerializer(Jackson3SupplierSerializer.INSTANCE); | ||||||||||
| MODULE = 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) and | ||||||||||
| * {@code DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES} disabled (set to false). | ||||||||||
| * | ||||||||||
| * @return a new ObjectMapper with the {@code jjwt-jackson} module registered and | ||||||||||
| * {@code JsonParser.Feature.STRICT_DUPLICATE_DETECTION} enabled (set to true) and | ||||||||||
| * {@code DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES} disabled (set to false). | ||||||||||
| * | ||||||||||
| * @since 0.12.4 | ||||||||||
| */ | ||||||||||
|
Comment on lines
+58
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| // package protected on purpose, do not expose to the public API | ||||||||||
| static ObjectMapper newObjectMapper() { | ||||||||||
| return builder().addModule(MODULE) | ||||||||||
| .configure(StreamReadFeature.STRICT_DUPLICATE_DETECTION, true) // https://github.com/jwtk/jjwt/issues/877 | ||||||||||
| .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) // https://github.com/jwtk/jjwt/issues/893 | ||||||||||
| .build(); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| protected final ObjectMapper objectMapper; | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Constructor using JJWT's default {@link ObjectMapper} singleton for serialization. | ||||||||||
| */ | ||||||||||
| public Jackson3Serializer() { | ||||||||||
| this(DEFAULT_OBJECT_MAPPER); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Creates a new Jackson Serializer that uses the specified {@link ObjectMapper} for serialization. | ||||||||||
| * | ||||||||||
| * @param objectMapper the ObjectMapper to use for serialization. | ||||||||||
| */ | ||||||||||
| public Jackson3Serializer(ObjectMapper objectMapper) { | ||||||||||
| Assert.notNull(objectMapper, "ObjectMapper cannot be null."); | ||||||||||
| this.objectMapper = objectMapper.rebuild().addModule(MODULE).build(); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| @Override | ||||||||||
| protected void doSerialize(T t, OutputStream out) throws Exception { | ||||||||||
| Assert.notNull(out, "OutputStream cannot be null."); | ||||||||||
|
|
||||||||||
| ObjectWriter writer = this.objectMapper.writer().without(AUTO_CLOSE_TARGET); | ||||||||||
| writer.writeValue(out, t); | ||||||||||
| } | ||||||||||
| } | ||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,53 @@ | ||||||
| /* | ||||||
| * Copyright (C) 2022 jsonwebtoken.io | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| * | ||||||
| * 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. | ||||||
| */ | ||||||
| package io.jsonwebtoken.jackson.io; | ||||||
|
|
||||||
|
|
||||||
| import io.jsonwebtoken.lang.Supplier; | ||||||
| import tools.jackson.core.JacksonException; | ||||||
| import tools.jackson.core.JsonGenerator; | ||||||
| import tools.jackson.databind.SerializationContext; | ||||||
| import tools.jackson.databind.ValueSerializer; | ||||||
| import tools.jackson.databind.ser.std.StdSerializer; | ||||||
|
|
||||||
| final class Jackson3SupplierSerializer extends StdSerializer<Supplier<?>> { | ||||||
|
|
||||||
| static final Jackson3SupplierSerializer INSTANCE = new Jackson3SupplierSerializer(); | ||||||
|
|
||||||
| public Jackson3SupplierSerializer() { | ||||||
| super(Supplier.class, false); | ||||||
| } | ||||||
|
|
||||||
| /** | ||||||
| * @param supplier | ||||||
| * @param generator | ||||||
| * @param provider | ||||||
| * @throws JacksonException | ||||||
| */ | ||||||
|
Comment on lines
+34
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: fill in, or remove javadoc |
||||||
| @Override | ||||||
| public void serialize(Supplier<?> supplier, JsonGenerator generator, SerializationContext provider) throws JacksonException { | ||||||
| Object value = supplier.get(); | ||||||
|
|
||||||
| if (value == null) { | ||||||
| provider.defaultSerializeNullValue(generator); | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| Class<?> clazz = value.getClass(); | ||||||
| ValueSerializer<Object> ser = provider.findTypedValueSerializer(clazz, true); | ||||||
| ser.serialize(value, generator, provider); | ||||||
| } | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| io.jsonwebtoken.jackson.io.Jackson3Deserializer |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| io.jsonwebtoken.jackson.io.Jackson3Serializer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file should be removed (it would be in the root of the project if it needs to be added)