From fee79ccb51873998762b81bd5fd8c2508175d6e1 Mon Sep 17 00:00:00 2001 From: hyunmin0317 Date: Thu, 22 Aug 2024 22:45:47 +0900 Subject: [PATCH] Abstract Jackson2 Set and List Deserializers --- ...actUnmodifiableCollectionDeserializer.java | 77 +++++++++++++++++++ .../UnmodifiableListDeserializer.java | 31 ++------ .../jackson2/UnmodifiableSetDeserializer.java | 29 ++----- 3 files changed, 92 insertions(+), 45 deletions(-) create mode 100644 core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java diff --git a/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java b/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java new file mode 100644 index 0000000000..5492755eb0 --- /dev/null +++ b/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java @@ -0,0 +1,77 @@ +/* + * Copyright 2024 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.jackson2; + +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.node.ArrayNode; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * Abstract base class for deserializers that create unmodifiable collections from JSON data. + * Subclasses like {@link UnmodifiableListDeserializer} and + * {@link UnmodifiableSetDeserializer} should implement the method to define the + * specific collection type and handle the deserialization logic. + * + * @param the type of the unmodifiable collection, such as {@link List} or {@link Set}. + * @author Hyunmin Choi + */ +abstract class AbstractUnmodifiableCollectionDeserializer extends JsonDeserializer { + + @Override + public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { + ObjectMapper mapper = (ObjectMapper) jp.getCodec(); + JsonNode node = mapper.readTree(jp); + return createUnmodifiableCollection(node, mapper); + } + + /** + * Creates an unmodifiable collection from the given JSON node. + * + * @param node the JSON node containing the data to be deserialized. + * @param mapper the {@link ObjectMapper} used to deserialize JSON data. + * @return an unmodifiable collection with the deserialized elements. + * @throws IOException if an error occurs during deserialization. + */ + protected abstract T createUnmodifiableCollection(JsonNode node, ObjectMapper mapper) throws IOException; + + /** + * Adds elements from the JSON node to the provided collection. + * + * @param node the JSON node containing the elements to add. + * @param mapper the {@link ObjectMapper} used for deserialization. + * @param collection the collection to which elements are added. + * @throws IOException if an error occurs during deserialization. + */ + protected void addElements(JsonNode node, ObjectMapper mapper, Collection collection) throws IOException { + if (node instanceof ArrayNode arrayNode) { + for (JsonNode elementNode : arrayNode) { + collection.add(mapper.readValue(elementNode.traverse(mapper), Object.class)); + } + } else if (node != null) { + collection.add(mapper.readValue(node.traverse(mapper), Object.class)); + } + } + +} diff --git a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableListDeserializer.java b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableListDeserializer.java index 8dc8ef286a..417c431b50 100644 --- a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableListDeserializer.java +++ b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableListDeserializer.java @@ -16,43 +16,28 @@ package org.springframework.security.jackson2; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -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.node.ArrayNode; - /** - * Custom deserializer for {@link UnmodifiableListDeserializer}. + * Custom deserializer for {@link UnmodifiableListMixin}. * * @author Rob Winch + * @author Hyunmin Choi * @since 5.0.2 * @see UnmodifiableListMixin */ -class UnmodifiableListDeserializer extends JsonDeserializer { +class UnmodifiableListDeserializer extends AbstractUnmodifiableCollectionDeserializer { @Override - public List deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = mapper.readTree(jp); + protected List createUnmodifiableCollection(JsonNode node, ObjectMapper mapper) throws IOException { List result = new ArrayList<>(); - if (node != null) { - if (node instanceof ArrayNode arrayNode) { - for (JsonNode elementNode : arrayNode) { - result.add(mapper.readValue(elementNode.traverse(mapper), Object.class)); - } - } - else { - result.add(mapper.readValue(node.traverse(mapper), Object.class)); - } - } + addElements(node, mapper, result); return Collections.unmodifiableList(result); } diff --git a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java index 74e19fa8bb..ed6e22cb79 100644 --- a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java +++ b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java @@ -16,43 +16,28 @@ package org.springframework.security.jackson2; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + import java.io.IOException; import java.util.Collections; import java.util.HashSet; import java.util.Set; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonProcessingException; -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.node.ArrayNode; - /** * Custom deserializer for {@link UnmodifiableSetMixin}. * * @author Jitendra Singh + * @author Hyunmin Choi * @since 4.2 * @see UnmodifiableSetMixin */ -class UnmodifiableSetDeserializer extends JsonDeserializer { +class UnmodifiableSetDeserializer extends AbstractUnmodifiableCollectionDeserializer { @Override - public Set deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { - ObjectMapper mapper = (ObjectMapper) jp.getCodec(); - JsonNode node = mapper.readTree(jp); + protected Set createUnmodifiableCollection(JsonNode node, ObjectMapper mapper) throws IOException { Set resultSet = new HashSet<>(); - if (node != null) { - if (node instanceof ArrayNode arrayNode) { - for (JsonNode elementNode : arrayNode) { - resultSet.add(mapper.readValue(elementNode.traverse(mapper), Object.class)); - } - } - else { - resultSet.add(mapper.readValue(node.traverse(mapper), Object.class)); - } - } + addElements(node, mapper, resultSet); return Collections.unmodifiableSet(resultSet); }