diff --git a/pom.xml b/pom.xml
index 09bebeb5b..225297442 100644
--- a/pom.xml
+++ b/pom.xml
@@ -276,6 +276,13 @@
test
+
+ org.msgpack
+ jackson-dataformat-msgpack
+ 0.9.8
+ test
+
+
edu.umd.cs.mtc
multithreadedtc
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 7ecc89d18..9358f36a7 100644
--- a/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java
+++ b/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java
@@ -32,13 +32,19 @@ 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.JsonParser;
+import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.deser.BeanDeserializerFactory;
+import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext;
+import com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer;
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
@@ -179,7 +185,7 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer lazyTypeHintPropertyName = typeHintPropertyName != null ? Lazy.of(typeHintPropertyName)
: newLazyTypeHintPropertyName(mapper, defaultTypingEnabled);
- return new TypeResolver(lazyTypeFactory, lazyTypeHintPropertyName);
+ return new TypeResolver(mapper, lazyTypeFactory, lazyTypeHintPropertyName);
}
private static Lazy newLazyTypeHintPropertyName(ObjectMapper mapper, Lazy defaultTypingEnabled) {
@@ -340,14 +346,13 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer typeFactory;
private final Supplier hintName;
- TypeResolver(Supplier typeFactory, Supplier hintName) {
+ TypeResolver(ObjectMapper mapper, Supplier typeFactory, Supplier hintName) {
+ this.mapper = mapper;
this.typeFactory = typeFactory;
this.hintName = hintName;
}
@@ -358,7 +363,7 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer type) throws IOException {
- JsonNode root = mapper.readTree(source);
+ JsonNode root = readTree(source);
JsonNode jsonNode = root.get(hintName.get());
if (jsonNode instanceof TextNode && jsonNode.asText() != null) {
@@ -367,6 +372,42 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer deserializer = JsonNodeDeserializer.getDeserializer(JsonNode.class);
+ DeserializationConfig cfg = mapper.getDeserializationConfig();
+
+ try (JsonParser parser = mapper.createParser(source)) {
+
+ cfg.initialize(parser);
+ JsonToken t = parser.currentToken();
+ if (t == null) {
+ t = parser.nextToken();
+ if (t == null) {
+ return cfg.getNodeFactory().missingNode();
+ }
+ }
+
+ /*
+ * Hokey pokey! Oh my.
+ */
+ DefaultDeserializationContext ctxt = new DefaultDeserializationContext.Impl(BeanDeserializerFactory.instance)
+ .createInstance(cfg, parser, mapper.getInjectableValues());
+ if (t == JsonToken.VALUE_NULL) {
+ return cfg.getNodeFactory().nullNode();
+ } else {
+ return deserializer.deserialize(parser, ctxt);
+ }
+ }
+ }
}
/**
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 16daa677c..c91e6b46f 100644
--- a/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java
+++ b/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java
@@ -32,6 +32,7 @@ import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
+import org.msgpack.jackson.dataformat.MessagePackFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.support.NullValue;
@@ -449,6 +450,7 @@ class GenericJackson2JsonRedisSerializerUnitTests {
@Test
void defaultSerializeAndDeserializeNullValueWithBuilderClass() {
+
GenericJackson2JsonRedisSerializer serializer = GenericJackson2JsonRedisSerializer.builder()
.objectMapper(new ObjectMapper().enableDefaultTyping(DefaultTyping.EVERYTHING, As.PROPERTY))
.build();
@@ -487,6 +489,31 @@ class GenericJackson2JsonRedisSerializerUnitTests {
assertThat(deserializedValue).isNull();
}
+ @Test // GH-2981
+ void defaultSerializeAndDeserializeWithCustomJsonFactory() {
+
+ GenericJackson2JsonRedisSerializer serializer = GenericJackson2JsonRedisSerializer.builder()
+ .objectMapper(
+ new ObjectMapper(new MessagePackFactory()).enableDefaultTyping(DefaultTyping.EVERYTHING, As.PROPERTY))
+ .build();
+
+ byte[] serializedValue = serializer.serialize(COMPLEX_OBJECT);
+
+ Object deserializedValue = serializer.deserialize(serializedValue, Object.class);
+ assertThat(deserializedValue).isEqualTo(COMPLEX_OBJECT);
+ }
+
+ @Test // GH-2981
+ void defaultSerializeAndDeserializeNullValueWithBuilderClassAndCustomJsonFactory() {
+
+ GenericJackson2JsonRedisSerializer serializer = GenericJackson2JsonRedisSerializer.builder()
+ .objectMapper(
+ new ObjectMapper(new MessagePackFactory()).enableDefaultTyping(DefaultTyping.EVERYTHING, As.PROPERTY))
+ .build();
+
+ serializeAndDeserializeNullValue(serializer);
+ }
+
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
NullValue nv = BeanUtils.instantiateClass(NullValue.class);