Browse Source
Fixes problems with serialization of complex attribute values of various framework types such as OAuth2AuthorizationRequest and OAuth2ClientAuthenticationToken. Closes gh-324 Closes gh-328pull/333/head
12 changed files with 523 additions and 1 deletions
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
|
||||
/** |
||||
* This mixin class is used to serialize/deserialize {@link HashSet}. |
||||
* |
||||
* @author Steve Riesenberg |
||||
* @see HashSet |
||||
* @see OAuth2ServerJackson2Module |
||||
* @since 0.1.2 |
||||
*/ |
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) |
||||
abstract class HashSetMixin { |
||||
|
||||
@JsonCreator |
||||
HashSetMixin(Set<?> set) { |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@
@@ -0,0 +1,65 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference; |
||||
import com.fasterxml.jackson.databind.JsonNode; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
||||
/** |
||||
* Utility class for {@code JsonNode}. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
*/ |
||||
abstract class JsonNodeUtils { |
||||
|
||||
static final TypeReference<Set<String>> STRING_SET = new TypeReference<Set<String>>() { |
||||
}; |
||||
|
||||
static final TypeReference<Map<String, Object>> STRING_OBJECT_MAP = new TypeReference<Map<String, Object>>() { |
||||
}; |
||||
|
||||
static String findStringValue(JsonNode jsonNode, String fieldName) { |
||||
if (jsonNode == null) { |
||||
return null; |
||||
} |
||||
JsonNode value = jsonNode.findValue(fieldName); |
||||
return (value != null && value.isTextual()) ? value.asText() : null; |
||||
} |
||||
|
||||
static <T> T findValue(JsonNode jsonNode, String fieldName, TypeReference<T> valueTypeReference, |
||||
ObjectMapper mapper) { |
||||
if (jsonNode == null) { |
||||
return null; |
||||
} |
||||
JsonNode value = jsonNode.findValue(fieldName); |
||||
return (value != null && value.isContainerNode()) ? mapper.convertValue(value, valueTypeReference) : null; |
||||
} |
||||
|
||||
static JsonNode findObjectNode(JsonNode jsonNode, String fieldName) { |
||||
if (jsonNode == null) { |
||||
return null; |
||||
} |
||||
JsonNode value = jsonNode.findValue(fieldName); |
||||
return (value != null && value.isObject()) ? value : null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,81 @@
@@ -0,0 +1,81 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException; |
||||
import com.fasterxml.jackson.core.JsonParser; |
||||
import com.fasterxml.jackson.databind.DeserializationContext; |
||||
import com.fasterxml.jackson.databind.JsonDeserializer; |
||||
import com.fasterxml.jackson.databind.JsonNode; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
import com.fasterxml.jackson.databind.util.StdConverter; |
||||
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType; |
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; |
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest.Builder; |
||||
|
||||
/** |
||||
* A {@code JsonDeserializer} for {@link OAuth2AuthorizationRequest}. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
* @see OAuth2AuthorizationRequest |
||||
* @see OAuth2AuthorizationRequestMixin |
||||
*/ |
||||
final class OAuth2AuthorizationRequestDeserializer extends JsonDeserializer<OAuth2AuthorizationRequest> { |
||||
|
||||
private static final StdConverter<JsonNode, AuthorizationGrantType> AUTHORIZATION_GRANT_TYPE_CONVERTER = new StdConverters.AuthorizationGrantTypeConverter(); |
||||
|
||||
@Override |
||||
public OAuth2AuthorizationRequest deserialize(JsonParser parser, DeserializationContext context) |
||||
throws IOException { |
||||
ObjectMapper mapper = (ObjectMapper) parser.getCodec(); |
||||
JsonNode root = mapper.readTree(parser); |
||||
return deserialize(parser, mapper, root); |
||||
} |
||||
|
||||
private OAuth2AuthorizationRequest deserialize(JsonParser parser, ObjectMapper mapper, JsonNode root) |
||||
throws JsonParseException { |
||||
AuthorizationGrantType authorizationGrantType = AUTHORIZATION_GRANT_TYPE_CONVERTER |
||||
.convert(JsonNodeUtils.findObjectNode(root, "authorizationGrantType")); |
||||
Builder builder = getBuilder(parser, authorizationGrantType); |
||||
builder.authorizationUri(JsonNodeUtils.findStringValue(root, "authorizationUri")); |
||||
builder.clientId(JsonNodeUtils.findStringValue(root, "clientId")); |
||||
builder.redirectUri(JsonNodeUtils.findStringValue(root, "redirectUri")); |
||||
builder.scopes(JsonNodeUtils.findValue(root, "scopes", JsonNodeUtils.STRING_SET, mapper)); |
||||
builder.state(JsonNodeUtils.findStringValue(root, "state")); |
||||
builder.additionalParameters( |
||||
JsonNodeUtils.findValue(root, "additionalParameters", JsonNodeUtils.STRING_OBJECT_MAP, mapper)); |
||||
builder.authorizationRequestUri(JsonNodeUtils.findStringValue(root, "authorizationRequestUri")); |
||||
builder.attributes(JsonNodeUtils.findValue(root, "attributes", JsonNodeUtils.STRING_OBJECT_MAP, mapper)); |
||||
return builder.build(); |
||||
} |
||||
|
||||
private Builder getBuilder(JsonParser parser, |
||||
AuthorizationGrantType authorizationGrantType) throws JsonParseException { |
||||
if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(authorizationGrantType)) { |
||||
return OAuth2AuthorizationRequest.authorizationCode(); |
||||
} |
||||
if (AuthorizationGrantType.IMPLICIT.equals(authorizationGrantType)) { |
||||
return OAuth2AuthorizationRequest.implicit(); |
||||
} |
||||
throw new JsonParseException(parser, "Invalid authorizationGrantType"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,43 @@
@@ -0,0 +1,43 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect; |
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; |
||||
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; |
||||
|
||||
/** |
||||
* This mixin class is used to serialize/deserialize {@link OAuth2AuthorizationRequest}. |
||||
* It also registers a custom deserializer {@link OAuth2AuthorizationRequestDeserializer}. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
* @see OAuth2AuthorizationRequest |
||||
* @see OAuth2AuthorizationRequestDeserializer |
||||
* @see OAuth2ServerJackson2Module |
||||
*/ |
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) |
||||
@JsonDeserialize(using = OAuth2AuthorizationRequestDeserializer.class) |
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, |
||||
isGetterVisibility = JsonAutoDetect.Visibility.NONE) |
||||
@JsonIgnoreProperties(ignoreUnknown = true) |
||||
abstract class OAuth2AuthorizationRequestMixin { |
||||
|
||||
} |
||||
@ -0,0 +1,51 @@
@@ -0,0 +1,51 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect; |
||||
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||
import com.fasterxml.jackson.annotation.JsonProperty; |
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
|
||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod; |
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken; |
||||
|
||||
/** |
||||
* This mixin class is used to serialize/deserialize {@link OAuth2ClientAuthenticationToken}. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
* @see OAuth2ClientAuthenticationToken |
||||
* @see OAuth2ServerJackson2Module |
||||
*/ |
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) |
||||
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, |
||||
isGetterVisibility = JsonAutoDetect.Visibility.NONE) |
||||
@JsonIgnoreProperties(value = { "authenticated" }, ignoreUnknown = true) |
||||
abstract class OAuth2ClientAuthenticationTokenMixin { |
||||
|
||||
@JsonCreator |
||||
OAuth2ClientAuthenticationTokenMixin(@JsonProperty("clientId") String clientId, |
||||
@JsonProperty("clientSecret") String clientSecret, |
||||
@JsonProperty("clientAuthenticationMethod") ClientAuthenticationMethod clientAuthenticationMethod, |
||||
@JsonProperty("additionalParameters") Map<String, Object> additionalParameters) { |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,73 @@
@@ -0,0 +1,73 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.HashSet; |
||||
|
||||
import com.fasterxml.jackson.core.Version; |
||||
import com.fasterxml.jackson.databind.module.SimpleModule; |
||||
|
||||
import org.springframework.security.jackson2.SecurityJackson2Modules; |
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; |
||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2ClientAuthenticationToken; |
||||
|
||||
/** |
||||
* Jackson {@code Module} for {@code spring-authorization-server}, that registers the |
||||
* following mix-in annotations: |
||||
* |
||||
* <ul> |
||||
* <li>{@link UnmodifiableMapMixin}</li> |
||||
* <li>{@link HashSetMixin}</li> |
||||
* <li>{@link OAuth2AuthorizationRequestMixin}</li> |
||||
* <li>{@link OAuth2ClientAuthenticationTokenMixin}</li> |
||||
* </ul> |
||||
* |
||||
* If not already enabled, default typing will be automatically enabled as type info is |
||||
* required to properly serialize/deserialize objects. In order to use this module just |
||||
* add it to your {@code ObjectMapper} configuration. |
||||
* |
||||
* <pre> |
||||
* ObjectMapper mapper = new ObjectMapper(); |
||||
* mapper.registerModule(new OAuth2ServerJackson2Module()); |
||||
* </pre> |
||||
* |
||||
* @author Steve Riesenberg |
||||
* @since 0.1.2 |
||||
* @see SecurityJackson2Modules |
||||
* @see UnmodifiableMapMixin |
||||
* @see HashSetMixin |
||||
* @see OAuth2AuthorizationRequestMixin |
||||
* @see OAuth2ClientAuthenticationTokenMixin |
||||
*/ |
||||
public class OAuth2ServerJackson2Module extends SimpleModule { |
||||
|
||||
public OAuth2ServerJackson2Module() { |
||||
super(OAuth2ServerJackson2Module.class.getName(), new Version(1, 0, 0, null, null, null)); |
||||
} |
||||
|
||||
@Override |
||||
public void setupModule(SetupContext context) { |
||||
SecurityJackson2Modules.enableDefaultTyping(context.getOwner()); |
||||
context.setMixInAnnotations(Collections.unmodifiableMap(Collections.emptyMap()).getClass(), |
||||
UnmodifiableMapMixin.class); |
||||
context.setMixInAnnotations(HashSet.class, HashSetMixin.class); |
||||
context.setMixInAnnotations(OAuth2AuthorizationRequest.class, OAuth2AuthorizationRequestMixin.class); |
||||
context.setMixInAnnotations(OAuth2ClientAuthenticationToken.class, OAuth2ClientAuthenticationTokenMixin.class); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode; |
||||
import com.fasterxml.jackson.databind.util.StdConverter; |
||||
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType; |
||||
|
||||
/** |
||||
* {@code StdConverter} implementations. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
*/ |
||||
abstract class StdConverters { |
||||
|
||||
static final class AuthorizationGrantTypeConverter extends StdConverter<JsonNode, AuthorizationGrantType> { |
||||
|
||||
@Override |
||||
public AuthorizationGrantType convert(JsonNode jsonNode) { |
||||
String value = JsonNodeUtils.findStringValue(jsonNode, "value"); |
||||
if (AuthorizationGrantType.AUTHORIZATION_CODE.getValue().equalsIgnoreCase(value)) { |
||||
return AuthorizationGrantType.AUTHORIZATION_CODE; |
||||
} |
||||
if (AuthorizationGrantType.IMPLICIT.getValue().equalsIgnoreCase(value)) { |
||||
return AuthorizationGrantType.IMPLICIT; |
||||
} |
||||
if (AuthorizationGrantType.CLIENT_CREDENTIALS.getValue().equalsIgnoreCase(value)) { |
||||
return AuthorizationGrantType.CLIENT_CREDENTIALS; |
||||
} |
||||
if (AuthorizationGrantType.PASSWORD.getValue().equalsIgnoreCase(value)) { |
||||
return AuthorizationGrantType.PASSWORD; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Collections; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
import com.fasterxml.jackson.core.JsonParser; |
||||
import com.fasterxml.jackson.databind.DeserializationContext; |
||||
import com.fasterxml.jackson.databind.JsonDeserializer; |
||||
import com.fasterxml.jackson.databind.JsonNode; |
||||
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
||||
/** |
||||
* A {@code JsonDeserializer} for {@link Collections#unmodifiableMap(Map)}. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
* @see Collections#unmodifiableMap(Map) |
||||
* @see UnmodifiableMapMixin |
||||
*/ |
||||
final class UnmodifiableMapDeserializer extends JsonDeserializer<Map<?, ?>> { |
||||
|
||||
@Override |
||||
public Map<?, ?> deserialize(JsonParser parser, DeserializationContext context) throws IOException { |
||||
ObjectMapper mapper = (ObjectMapper) parser.getCodec(); |
||||
JsonNode mapNode = mapper.readTree(parser); |
||||
Map<String, Object> result = new LinkedHashMap<>(); |
||||
if (mapNode != null && mapNode.isObject()) { |
||||
Iterable<Map.Entry<String, JsonNode>> fields = mapNode::fields; |
||||
for (Map.Entry<String, JsonNode> field : fields) { |
||||
result.put(field.getKey(), mapper.readValue(field.getValue().traverse(mapper), Object.class)); |
||||
} |
||||
} |
||||
return Collections.unmodifiableMap(result); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,45 @@
@@ -0,0 +1,45 @@
|
||||
/* |
||||
* Copyright 2002-2020 the original author or authors. |
||||
* |
||||
* 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 |
||||
* |
||||
* https://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 org.springframework.security.oauth2.server.authorization.jackson2; |
||||
|
||||
import java.util.Collections; |
||||
import java.util.Map; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; |
||||
|
||||
/** |
||||
* This mixin class is used to serialize/deserialize |
||||
* {@link Collections#unmodifiableMap(Map)}. It also registers a custom deserializer |
||||
* {@link UnmodifiableMapDeserializer}. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.1.2 |
||||
* @see Collections#unmodifiableMap(Map) |
||||
* @see UnmodifiableMapDeserializer |
||||
* @see OAuth2ServerJackson2Module |
||||
*/ |
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) |
||||
@JsonDeserialize(using = UnmodifiableMapDeserializer.class) |
||||
abstract class UnmodifiableMapMixin { |
||||
|
||||
@JsonCreator |
||||
UnmodifiableMapMixin(Map<?, ?> map) { |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue