diff --git a/pom.xml b/pom.xml
index 4bd510786b..0c1a061422 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-redis
- 3.0.0-SNAPSHOT
+ 3.0.0-GH-2322-SNAPSHOT
Spring Data Redis
Spring Data module for Redis
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 8fca10fbd6..9b0aa53e54 100644
--- a/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java
+++ b/src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java
@@ -16,8 +16,11 @@
package org.springframework.data.redis.serializer;
import java.io.IOException;
+import java.util.Collections;
+import java.util.function.Supplier;
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.StringUtils;
@@ -25,18 +28,24 @@
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.databind.JavaType;
+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.jsontype.PolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.node.TextNode;
import com.fasterxml.jackson.databind.ser.SerializerFactory;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.fasterxml.jackson.databind.type.TypeFactory;
/**
* Generic Jackson 2-based {@link RedisSerializer} that maps {@link Object objects} to JSON using dynamic typing.
+ *
+ * JSON reading and writing can be customized by configuring {@link JacksonObjectReader} respective
+ * {@link JacksonObjectWriter}.
*
* @author Christoph Strobl
* @author Mark Paluch
@@ -47,6 +56,14 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer defaultTypingEnabled;
+
+ private final TypeResolver typeResolver;
+
/**
* Creates {@link GenericJackson2JsonRedisSerializer} and configures {@link ObjectMapper} for default typing.
*/
@@ -59,13 +76,30 @@ public GenericJackson2JsonRedisSerializer() {
* given {@literal name}. In case of an {@literal empty} or {@literal null} String the default
* {@link JsonTypeInfo.Id#CLASS} will be used.
*
- * @param classPropertyTypeName Name of the JSON property holding type information. Can be {@literal null}.
+ * @param classPropertyTypeName name of the JSON property holding type information. Can be {@literal null}.
* @see ObjectMapper#activateDefaultTypingAsProperty(PolymorphicTypeValidator, DefaultTyping, String)
* @see ObjectMapper#activateDefaultTyping(PolymorphicTypeValidator, DefaultTyping, As)
*/
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {
+ this(classPropertyTypeName, JacksonObjectReader.create(), JacksonObjectWriter.create());
+ }
+
+ /**
+ * Creates {@link GenericJackson2JsonRedisSerializer} and configures {@link ObjectMapper} for default typing using the
+ * given {@literal name}. In case of an {@literal empty} or {@literal null} String the default
+ * {@link JsonTypeInfo.Id#CLASS} will be used.
+ *
+ * @param classPropertyTypeName name of the JSON property holding type information. Can be {@literal null}.
+ * @param reader the {@link JacksonObjectReader} function to read objects using {@link ObjectMapper}.
+ * @param writer the {@link JacksonObjectWriter} function to write objects using {@link ObjectMapper}.
+ * @see ObjectMapper#activateDefaultTypingAsProperty(PolymorphicTypeValidator, DefaultTyping, String)
+ * @see ObjectMapper#activateDefaultTyping(PolymorphicTypeValidator, DefaultTyping, As)
+ * @since 3.0
+ */
+ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName, JacksonObjectReader reader,
+ JacksonObjectWriter writer) {
- this(new ObjectMapper());
+ this(new ObjectMapper(), reader, writer, classPropertyTypeName);
// simply setting {@code mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)} does not help here since we need
// the type hint embedded for deserialization using the default typing feature.
@@ -87,9 +121,57 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
* @param mapper must not be {@literal null}.
*/
public GenericJackson2JsonRedisSerializer(ObjectMapper mapper) {
+ this(mapper, JacksonObjectReader.create(), JacksonObjectWriter.create());
+ }
+
+ /**
+ * Setting a custom-configured {@link ObjectMapper} is one way to take further control of the JSON serialization
+ * process. For example, an extended {@link SerializerFactory} can be configured that provides custom serializers for
+ * specific types.
+ *
+ * @param mapper must not be {@literal null}.
+ * @param reader the {@link JacksonObjectReader} function to read objects using {@link ObjectMapper}.
+ * @param writer the {@link JacksonObjectWriter} function to write objects using {@link ObjectMapper}.
+ * @since 3.0
+ */
+ public GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectReader reader,
+ JacksonObjectWriter writer) {
+ this(mapper, reader, writer, null);
+ }
+
+ private GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectReader reader,
+ JacksonObjectWriter writer, @Nullable String typeHintPropertyName) {
Assert.notNull(mapper, "ObjectMapper must not be null!");
+ Assert.notNull(reader, "Reader must not be null!");
+ Assert.notNull(writer, "Writer must not be null!");
+
this.mapper = mapper;
+ this.reader = reader;
+ this.writer = writer;
+
+ this.defaultTypingEnabled = Lazy.of(() -> mapper.getSerializationConfig().getDefaultTyper(null) != null);
+
+ Supplier typeHintPropertyNameSupplier;
+
+ if (typeHintPropertyName == null) {
+
+ typeHintPropertyNameSupplier = Lazy.of(() -> {
+ if (defaultTypingEnabled.get()) {
+ return null;
+ }
+
+ return mapper.getDeserializationConfig().getDefaultTyper(null)
+ .buildTypeDeserializer(mapper.getDeserializationConfig(),
+ mapper.getTypeFactory().constructType(Object.class), Collections.emptyList())
+ .getPropertyName();
+
+ }).or("@class");
+ } else {
+ typeHintPropertyNameSupplier = () -> typeHintPropertyName;
+ }
+
+ this.typeResolver = new TypeResolver(Lazy.of(mapper::getTypeFactory), typeHintPropertyNameSupplier);
}
/**
@@ -116,8 +198,8 @@ public byte[] serialize(@Nullable Object source) throws SerializationException {
}
try {
- return mapper.writeValueAsBytes(source);
- } catch (JsonProcessingException e) {
+ return writer.write(mapper, source);
+ } catch (IOException e) {
throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
}
}
@@ -134,6 +216,7 @@ public Object deserialize(@Nullable byte[] source) throws SerializationException
* @throws SerializationException
*/
@Nullable
+ @SuppressWarnings("unchecked")
public T deserialize(@Nullable byte[] source, Class type) throws SerializationException {
Assert.notNull(type,
@@ -144,12 +227,53 @@ public T deserialize(@Nullable byte[] source, Class type) throws Serializ
}
try {
- return mapper.readValue(source, type);
+ return (T) reader.read(mapper, source, resolveType(source, type));
} catch (Exception ex) {
throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
}
}
+ protected JavaType resolveType(byte[] source, Class> type) throws IOException {
+
+ if (!type.equals(Object.class) || !defaultTypingEnabled.get()) {
+ return typeResolver.constructType(type);
+ }
+
+ return typeResolver.resolveType(source, type);
+ }
+
+ static class TypeResolver {
+
+ // need a separate instance to bypass class hint checks
+ private final ObjectMapper mapper = new ObjectMapper();
+
+ private final Supplier typeFactory;
+ private final Supplier hintName;
+
+ public TypeResolver(Supplier typeFactory, Supplier hintName) {
+
+ this.typeFactory = typeFactory;
+ this.hintName = hintName;
+ }
+
+ protected JavaType constructType(Class> type) {
+ return typeFactory.get().constructType(type);
+ }
+
+ protected JavaType resolveType(byte[] source, Class> type) throws IOException {
+
+ JsonNode root = mapper.readTree(source);
+ JsonNode jsonNode = root.get(hintName.get());
+
+ if (jsonNode instanceof TextNode && jsonNode.asText() != null) {
+ return typeFactory.get().constructFromCanonical(jsonNode.asText());
+ }
+
+ return constructType(type);
+ }
+
+ }
+
/**
* {@link StdSerializer} adding class information required by default typing. This allows de-/serialization of
* {@link NullValue}.
@@ -172,8 +296,7 @@ private static class NullValueSerializer extends StdSerializer {
}
@Override
- public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider)
- throws IOException {
+ public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
jgen.writeStringField(classIdentifier, NullValue.class.getName());
@@ -186,4 +309,5 @@ public void serializeWithType(NullValue value, JsonGenerator gen, SerializerProv
serialize(value, gen, serializers);
}
}
+
}
diff --git a/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java b/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java
index ed41ea1462..614b57d61e 100644
--- a/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java
+++ b/src/main/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializer.java
@@ -31,35 +31,98 @@
* Jackson's and
* Jackson Databind {@link ObjectMapper}.
*
- * This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances.
+ * This serializer can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances.
* Note:Null objects are serialized as empty arrays and vice versa.
+ *
+ * JSON reading and writing can be customized by configuring {@link JacksonObjectReader} respective
+ * {@link JacksonObjectWriter}.
*
* @author Thomas Darimont
+ * @author Mark Paluch
* @since 1.2
*/
public class Jackson2JsonRedisSerializer implements RedisSerializer {
+ /**
+ * @deprecated since 3.0 for removal.
+ */
+ @Deprecated(since = "3.0", forRemoval = true) //
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private final JavaType javaType;
- private ObjectMapper objectMapper = new ObjectMapper();
+ private ObjectMapper mapper;
+
+ private final JacksonObjectReader reader;
+
+ private final JacksonObjectWriter writer;
/**
* Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link Class}.
*
- * @param type
+ * @param type must not be {@literal null}.
*/
public Jackson2JsonRedisSerializer(Class type) {
- this.javaType = getJavaType(type);
+ this(new ObjectMapper(), type);
}
/**
* Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link JavaType}.
*
- * @param javaType
+ * @param javaType must not be {@literal null}.
*/
public Jackson2JsonRedisSerializer(JavaType javaType) {
+ this(new ObjectMapper(), javaType);
+ }
+
+ /**
+ * Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link Class}.
+ *
+ * @param mapper must not be {@literal null}.
+ * @param type must not be {@literal null}.
+ * @since 3.0
+ */
+ public Jackson2JsonRedisSerializer(ObjectMapper mapper, Class type) {
+
+ Assert.notNull(mapper, "ObjectMapper must not be null");
+ Assert.notNull(type, "Java type must not be null");
+
+ this.javaType = getJavaType(type);
+ this.mapper = mapper;
+ this.reader = JacksonObjectReader.create();
+ this.writer = JacksonObjectWriter.create();
+ }
+
+ /**
+ * Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link JavaType}.
+ *
+ * @param mapper must not be {@literal null}.
+ * @param javaType must not be {@literal null}.
+ * @since 3.0
+ */
+ public Jackson2JsonRedisSerializer(ObjectMapper mapper, JavaType javaType) {
+ this(mapper, javaType, JacksonObjectReader.create(), JacksonObjectWriter.create());
+ }
+
+ /**
+ * Creates a new {@link Jackson2JsonRedisSerializer} for the given target {@link JavaType}.
+ *
+ * @param mapper must not be {@literal null}.
+ * @param javaType must not be {@literal null}.
+ * @param reader the {@link JacksonObjectReader} function to read objects using {@link ObjectMapper}.
+ * @param writer the {@link JacksonObjectWriter} function to write objects using {@link ObjectMapper}.
+ * @since 3.0
+ */
+ public Jackson2JsonRedisSerializer(ObjectMapper mapper, JavaType javaType, JacksonObjectReader reader,
+ JacksonObjectWriter writer) {
+
+ Assert.notNull(mapper, "ObjectMapper must not be null!");
+ Assert.notNull(reader, "Reader must not be null!");
+ Assert.notNull(writer, "Writer must not be null!");
+
+ this.mapper = mapper;
+ this.reader = reader;
+ this.writer = writer;
this.javaType = javaType;
}
@@ -70,7 +133,7 @@ public T deserialize(@Nullable byte[] bytes) throws SerializationException {
return null;
}
try {
- return (T) this.objectMapper.readValue(bytes, 0, bytes.length, javaType);
+ return (T) this.reader.read(this.mapper, bytes, javaType);
} catch (Exception ex) {
throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
}
@@ -83,7 +146,7 @@ public byte[] serialize(@Nullable Object t) throws SerializationException {
return SerializationUtils.EMPTY_ARRAY;
}
try {
- return this.objectMapper.writeValueAsBytes(t);
+ return this.writer.write(this.mapper, t);
} catch (Exception ex) {
throw new SerializationException("Could not write JSON: " + ex.getMessage(), ex);
}
@@ -97,11 +160,15 @@ public byte[] serialize(@Nullable Object t) throws SerializationException {
* process. For example, an extended {@link SerializerFactory} can be configured that provides custom serializers for
* specific types. The other option for refining the serialization process is to use Jackson's provided annotations on
* the types to be serialized, in which case a custom-configured ObjectMapper is unnecessary.
+ *
+ * @deprecated since 3.0, use {@link #Jackson2JsonRedisSerializer(ObjectMapper, Class) constructor creation} to
+ * configure the object mapper.
*/
- public void setObjectMapper(ObjectMapper objectMapper) {
+ @Deprecated(since = "3.0", forRemoval = true)
+ public void setObjectMapper(ObjectMapper mapper) {
- Assert.notNull(objectMapper, "'objectMapper' must not be null");
- this.objectMapper = objectMapper;
+ Assert.notNull(mapper, "'objectMapper' must not be null");
+ this.mapper = mapper;
}
/**
diff --git a/src/main/java/org/springframework/data/redis/serializer/JacksonObjectReader.java b/src/main/java/org/springframework/data/redis/serializer/JacksonObjectReader.java
new file mode 100644
index 0000000000..46552db37d
--- /dev/null
+++ b/src/main/java/org/springframework/data/redis/serializer/JacksonObjectReader.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2022 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.data.redis.serializer;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Defines the contract for Object Mapping readers. Implementations of this interface can deserialize a given byte array
+ * holding JSON to an Object considering the target type.
+ *
+ * Reader functions can customize how the actual JSON is being deserialized by e.g. obtaining a customized
+ * {@link com.fasterxml.jackson.databind.ObjectReader} applying serialization features, date formats, or views.
+ *
+ * @author Mark Paluch
+ * @since 3.0
+ */
+@FunctionalInterface
+public interface JacksonObjectReader {
+
+ /**
+ * Read an object graph from the given root JSON into a Java object considering the {@link JavaType}.
+ *
+ * @param mapper the object mapper to use.
+ * @param source the JSON to deserialize.
+ * @param type the Java target type
+ * @return the deserialized Java object.
+ * @throws IOException if an I/O error or JSON deserialization error occurs.
+ */
+ Object read(ObjectMapper mapper, byte[] source, JavaType type) throws IOException;
+
+ /**
+ * Create a default {@link JacksonObjectReader} delegating to {@link ObjectMapper#readValue(InputStream, JavaType)}.
+ *
+ * @return the default {@link JacksonObjectReader}.
+ */
+ static JacksonObjectReader create() {
+ return (mapper, source, type) -> mapper.readValue(source, 0, source.length, type);
+ }
+
+}
diff --git a/src/main/java/org/springframework/data/redis/serializer/JacksonObjectWriter.java b/src/main/java/org/springframework/data/redis/serializer/JacksonObjectWriter.java
new file mode 100644
index 0000000000..64ecd44de9
--- /dev/null
+++ b/src/main/java/org/springframework/data/redis/serializer/JacksonObjectWriter.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 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.data.redis.serializer;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * Defines the contract for Object Mapping writers. Implementations of this interface can serialize a given Object to a
+ * {@code byte[]} containing JSON.
+ *
+ * Writer functions can customize how the actual JSON is being written by e.g. obtaining a customized
+ * {@link com.fasterxml.jackson.databind.ObjectWriter} applying serialization features, date formats, or views.
+ *
+ * @author Mark Paluch
+ * @since 3.0
+ */
+@FunctionalInterface
+public interface JacksonObjectWriter {
+
+ /**
+ * Write the object graph with the given root {@code source} as byte array.
+ *
+ * @param mapper the object mapper to use.
+ * @param source the root of the object graph to marshal.
+ * @return a byte array containing the serialized object graph.
+ * @throws IOException if an I/O error or JSON serialization error occurs.
+ */
+ byte[] write(ObjectMapper mapper, Object source) throws IOException;
+
+ /**
+ * Create a default {@link JacksonObjectWriter} delegating to {@link ObjectMapper#writeValueAsBytes(Object)}.
+ *
+ * @return the default {@link JacksonObjectWriter}.
+ */
+ static JacksonObjectWriter create() {
+ return ObjectMapper::writeValueAsBytes;
+ }
+
+}
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 f13d7cf1a8..ae565f7eab 100644
--- a/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java
+++ b/src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java
@@ -21,6 +21,7 @@
import static org.springframework.util.ObjectUtils.*;
import lombok.Data;
+import lombok.ToString;
import java.io.IOException;
@@ -31,6 +32,7 @@
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
+import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
@@ -162,6 +164,52 @@ void deserializeShouldBeAbleToRestoreFinalObjectAfterSerialization() {
assertThat(serializer.deserialize(serializer.serialize(source))).isEqualTo(source);
}
+ @Test // GH-2322
+ void shouldConsiderWriter() {
+
+ User user = new User();
+ user.email = "walter@heisenberg.com";
+ user.id = 42;
+ user.name = "Walter White";
+
+ GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer((String) null,
+ JacksonObjectReader.create(), (mapper, source) -> {
+ return mapper.writerWithView(Views.Basic.class).writeValueAsBytes(source);
+ });
+
+ byte[] result = serializer.serialize(user);
+
+ assertThat(new String(result)).contains("id").contains("name").doesNotContain("email");
+ }
+
+ @Test // GH-2322
+ void shouldConsiderReader() {
+
+ User user = new User();
+ user.email = "walter@heisenberg.com";
+ user.id = 42;
+ user.name = "Walter White";
+
+ GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer((String) null,
+ (mapper, source, type) -> {
+ if (type.getRawClass() == User.class) {
+ return mapper.readerWithView(Views.Basic.class).forType(type).readValue(source);
+ }
+ return mapper.readValue(source, type);
+ }, JacksonObjectWriter.create());
+
+ byte[] serializedValue = serializer.serialize(user);
+
+ Object result = serializer.deserialize(serializedValue);
+ assertThat(result).isInstanceOf(User.class).satisfies(it -> {
+ User u = (User) it;
+ assertThat(u.id).isEqualTo(user.id);
+ assertThat(u.name).isEqualTo(user.name);
+ assertThat(u.email).isNull();
+ assertThat(u.mobile).isNull();
+ });
+ }
+
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
NullValue nv = BeanUtils.instantiateClass(NullValue.class);
@@ -252,4 +300,19 @@ public boolean equals(Object obj) {
}
}
+ @ToString
+ static class User {
+ @JsonView(Views.Basic.class) public int id;
+ @JsonView(Views.Basic.class) public String name;
+ @JsonView(Views.Detailed.class) public String email;
+ @JsonView(Views.Detailed.class) public String mobile;
+ }
+
+ static class Views {
+ interface Basic {}
+
+ interface Detailed {}
+
+ }
+
}
diff --git a/src/test/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializerTests.java b/src/test/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializerTests.java
index f0d57830ce..1da6e10b8f 100644
--- a/src/test/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializerTests.java
+++ b/src/test/java/org/springframework/data/redis/serializer/Jackson2JsonRedisSerializerTests.java
@@ -24,9 +24,15 @@
import org.springframework.data.redis.Person;
import org.springframework.data.redis.PersonObjectFactory;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+
/**
+ * Unit tests for {@link Jackson2JsonRedisSerializer}.
+ *
* @author Thomas Darimont
* @author Christoph Strobl
+ * @author Mark Paluch
*/
class Jackson2JsonRedisSerializerTests {
@@ -64,4 +70,14 @@ void testJackson2JsonSerilizerThrowsExceptionWhenSettingNullObjectMapper() {
assertThatIllegalArgumentException().isThrownBy(() -> serializer.setObjectMapper(null));
}
+ @Test // GH-2322
+ void shouldConsiderWriter() {
+
+ serializer = new Jackson2JsonRedisSerializer<>(new ObjectMapper(),
+ TypeFactory.defaultInstance().constructType(Person.class), JacksonObjectReader.create(),
+ (mapper, source) -> "foo".getBytes());
+ Person person = new PersonObjectFactory().instance();
+ assertThat(serializer.serialize(person)).isEqualTo("foo".getBytes());
+ }
+
}