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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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 @@ |
|||||||
|
/* |
||||||
|
* 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