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..a58e5812486 --- /dev/null +++ b/core/src/main/java/org/springframework/security/jackson2/AbstractUnmodifiableCollectionDeserializer.java @@ -0,0 +1,68 @@ +/* + * 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 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; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; + +/** + * 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); + 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 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. + */ + 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 8dc8ef286a5..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,44 +16,24 @@ package org.springframework.security.jackson2; -import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; 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); - 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)); - } - } - 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 74e19fa8bbc..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,44 +16,24 @@ package org.springframework.security.jackson2; -import java.io.IOException; +import java.util.Collection; 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); - 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)); - } - } - return Collections.unmodifiableSet(resultSet); + Set createUnmodifiableCollection(Collection values) { + return Collections.unmodifiableSet(new HashSet<>(values)); } }