From b43c98a1a57db010f450be39c698afb8586df9cb Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 13 Jul 2022 16:05:02 +0200 Subject: [PATCH] Introduce custom StdTypeResolverBuilder to support primitive arrays without type hints. Closes: #2361 Original Pull Request: #2364 --- .../GenericJackson2JsonRedisSerializer.java | 63 +++++++++++++++++-- ...cJackson2JsonRedisSerializerUnitTests.java | 25 ++++++++ 2 files changed, 84 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java b/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java index 533133fbe..39dd5cc93 100644 --- a/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java +++ b/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java @@ -23,11 +23,14 @@ import org.springframework.cache.support.NullValue; import org.springframework.data.util.Lazy; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo.As; import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -35,6 +38,7 @@ import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; +import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.TextNode; import com.fasterxml.jackson.databind.ser.SerializerFactory; @@ -105,12 +109,15 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer defaultImpl) { + return this; + } + + /** + * Method called to check if the default type handler should be used for given type. Note: "natural types" (String, + * Boolean, Integer, Double) will never use typing; that is both due to them being concrete and final, and since + * actual serializers and deserializers will also ignore any attempts to enforce typing. + */ + public boolean useForType(JavaType t) { + + if (t.isJavaLangObject()) { + return true; + } + + while (t.isArrayType()) { + t = t.getContentType(); + } + + if (ClassUtils.isPrimitiveOrWrapper(t.getRawClass())) { + return false; + } + + // 19-Apr-2016, tatu: ReferenceType like Optional also requires similar handling: + while (t.isReferenceType()) { + t = t.getReferencedType(); + } + + // [databind#88] Should not apply to JSON tree models: + return !TreeNode.class.isAssignableFrom(t.getRawClass()); + } + } } diff --git a/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java b/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java index 5c4e3d67b..238e74004 100644 --- a/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java +++ b/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java @@ -160,9 +160,26 @@ class GenericJackson2JsonRedisSerializerUnitTests { FinalObject source = new FinalObject(); source.longValue = 1L; + source.myArray = new int[] { 1, 2, 3 }; source.simpleObject = new SimpleObject(2L); assertThat(serializer.deserialize(serializer.serialize(source))).isEqualTo(source); + assertThat(serializer.deserialize( + ("{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$FinalObject\",\"longValue\":1,\"myArray\":[1,2,3],\n" + + "\"simpleObject\":{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$SimpleObject\",\"longValue\":2}}") + .getBytes())).isEqualTo(source); + } + + @Test // GH-2361 + void shouldDeserializeArrayWithoutTypeHint() { + + GenericJackson2JsonRedisSerializer gs = new GenericJackson2JsonRedisSerializer(); + CountAndArray result = (CountAndArray) gs.deserialize( + ("{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$CountAndArray\", \"count\":1, \"available\":[0,1]}") + .getBytes()); + + assertThat(result.getCount()).isEqualTo(1); + assertThat(result.getAvailable()).containsExactly(0, 1); } @Test // GH-2322 @@ -300,6 +317,7 @@ class GenericJackson2JsonRedisSerializerUnitTests { @Data static final class FinalObject { public Long longValue; + public int[] myArray; SimpleObject simpleObject; } @@ -349,4 +367,11 @@ class GenericJackson2JsonRedisSerializerUnitTests { interface Detailed {} } + + @Data + static class CountAndArray { + + private int count; + private int[] available; + } }