From a84a809d54555f6fe5cd2367dde92b6f60b8b24f Mon Sep 17 00:00:00 2001 From: hyunmin0317 Date: Thu, 22 Aug 2024 22:45:47 +0900 Subject: [PATCH 1/2] 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 00000000000..5492755eb05 --- /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 8dc8ef286a5..417c431b50a 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 74e19fa8bbc..ed6e22cb796 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); } From 7ed40ef230b33dbdcff12b79636abcb1f2692b1d Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Tue, 3 Sep 2024 17:08:26 -0600 Subject: [PATCH 2/2] Polish Abstract Deserializer --- ...actUnmodifiableCollectionDeserializer.java | 57 ++++++++----------- .../UnmodifiableListDeserializer.java | 11 +--- .../jackson2/UnmodifiableSetDeserializer.java | 11 +--- 3 files changed, 30 insertions(+), 49 deletions(-) diff --git a/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java b/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java index 5492755eb05..a58e5812486 100644 --- a/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java +++ b/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java @@ -16,6 +16,12 @@ package org.springframework.security.jackson2; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; @@ -23,18 +29,14 @@ 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. + * 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}. + * @param the type of the unmodifiable collection, such as {@link List} or + * {@link Set}. * @author Hyunmin Choi */ abstract class AbstractUnmodifiableCollectionDeserializer extends JsonDeserializer { @@ -43,35 +45,24 @@ abstract class AbstractUnmodifiableCollectionDeserializer extends JsonDeseria public T deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { ObjectMapper mapper = (ObjectMapper) jp.getCodec(); JsonNode node = mapper.readTree(jp); - return createUnmodifiableCollection(node, mapper); + Collection values = new ArrayList<>(); + if (node instanceof ArrayNode arrayNode) { + for (JsonNode elementNode : arrayNode) { + values.add(mapper.readValue(elementNode.traverse(mapper), Object.class)); + } + } + else if (node != null) { + values.add(mapper.readValue(node.traverse(mapper), Object.class)); + } + return createUnmodifiableCollection(values); } /** * 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. + * @param values the values to add to the unmodifiable collection * @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)); - } - } + abstract T createUnmodifiableCollection(Collection values) throws IOException; } 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 417c431b50a..271432af6e6 100644 --- a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableListDeserializer.java +++ b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableListDeserializer.java @@ -16,11 +16,8 @@ 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.Collection; import java.util.Collections; import java.util.List; @@ -35,10 +32,8 @@ class UnmodifiableListDeserializer extends AbstractUnmodifiableCollectionDeserializer { @Override - protected List createUnmodifiableCollection(JsonNode node, ObjectMapper mapper) throws IOException { - List result = new ArrayList<>(); - addElements(node, mapper, result); - return Collections.unmodifiableList(result); + List createUnmodifiableCollection(Collection values) { + return Collections.unmodifiableList(new ArrayList<>(values)); } } 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 ed6e22cb796..75600478cd2 100644 --- a/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java +++ b/core/src/main/java/org/springframework/security/jackson2/UnmodifiableSetDeserializer.java @@ -16,10 +16,7 @@ package org.springframework.security.jackson2; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; - -import java.io.IOException; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -35,10 +32,8 @@ class UnmodifiableSetDeserializer extends AbstractUnmodifiableCollectionDeserializer { @Override - protected Set createUnmodifiableCollection(JsonNode node, ObjectMapper mapper) throws IOException { - Set resultSet = new HashSet<>(); - addElements(node, mapper, resultSet); - return Collections.unmodifiableSet(resultSet); + Set createUnmodifiableCollection(Collection values) { + return Collections.unmodifiableSet(new HashSet<>(values)); } }