Skip to content

Commit 58ef24b

Browse files
committed
feat: add custom NullValueSerializer initializer
1 parent 3ab09fb commit 58ef24b

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,39 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
120120
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName, JacksonObjectReader reader,
121121
JacksonObjectWriter writer) {
122122

123+
this(classPropertyTypeName, reader, writer, null);
124+
}
125+
126+
/**
127+
* Creates {@link GenericJackson2JsonRedisSerializer} initialized with an {@link ObjectMapper} configured for default
128+
* typing using the given {@link String name} along with the given, required {@link JacksonObjectReader} and
129+
* {@link JacksonObjectWriter} used to read/write {@link Object Objects} de/serialized as JSON,
130+
* optionally customized {@link NullValueSerializer}.
131+
* <p>
132+
* In case {@link String name} is {@literal empty} or {@literal null}, then {@link JsonTypeInfo.Id#CLASS} will be
133+
* used.
134+
* <p>
135+
* In case {@link StdSerializer} is {@literal null}, then a default {@link NullValueSerializer} will be registered.
136+
*
137+
* @param classPropertyTypeName {@link String name} of the JSON property holding type information; can be
138+
* {@literal null}.
139+
* @param reader {@link JacksonObjectReader} function to read objects using {@link ObjectMapper}.
140+
* @param writer {@link JacksonObjectWriter} function to write objects using {@link ObjectMapper}.
141+
* @param nullValueSerializer {@link StdSerializer} to serialize {@link NullValue} instances.
142+
* @see ObjectMapper#activateDefaultTypingAsProperty(PolymorphicTypeValidator, DefaultTyping, String)
143+
* @see ObjectMapper#activateDefaultTyping(PolymorphicTypeValidator, DefaultTyping, As)
144+
* @since 3.3
145+
*/
146+
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName, JacksonObjectReader reader,
147+
JacksonObjectWriter writer, @Nullable StdSerializer<NullValue> nullValueSerializer) {
148+
123149
this(new ObjectMapper(), reader, writer, classPropertyTypeName);
124150

125-
registerNullValueSerializer(this.mapper, classPropertyTypeName);
151+
if (nullValueSerializer == null) {
152+
registerNullValueSerializer(this.mapper, classPropertyTypeName);
153+
} else {
154+
registerCustomNullValueSerializer(nullValueSerializer);
155+
}
126156

127157
StdTypeResolverBuilder typer = TypeResolverBuilder.forEverything(this.mapper).init(JsonTypeInfo.Id.CLASS, null)
128158
.inclusion(JsonTypeInfo.As.PROPERTY);
@@ -231,6 +261,10 @@ public static void registerNullValueSerializer(ObjectMapper objectMapper, @Nulla
231261
objectMapper.registerModule(new SimpleModule().addSerializer(new NullValueSerializer(classPropertyTypeName)));
232262
}
233263

264+
private void registerCustomNullValueSerializer(StdSerializer<NullValue> nullValueSerializer) {
265+
this.mapper.registerModule(new SimpleModule().addSerializer(nullValueSerializer));
266+
}
267+
234268
/**
235269
* Gets the configured {@link ObjectMapper} used internally by this {@link GenericJackson2JsonRedisSerializer} to
236270
* de/serialize {@link Object objects} as {@literal JSON}.

src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
import java.util.concurrent.atomic.AtomicReference;
4141
import java.util.function.Consumer;
4242

43+
import com.fasterxml.jackson.core.JsonGenerator;
44+
import com.fasterxml.jackson.databind.SerializerProvider;
45+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
46+
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
4347
import org.junit.jupiter.api.Test;
4448
import org.mockito.Mockito;
4549

@@ -420,7 +424,7 @@ void deserializesJavaTimeFrimBytes() {
420424
}
421425

422426
@Test // GH-2601
423-
public void internalObjectMapperCustomization() {
427+
void internalObjectMapperCustomization() {
424428

425429
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
426430

@@ -438,14 +442,49 @@ public void internalObjectMapperCustomization() {
438442
}
439443

440444
@Test // GH-2601
441-
public void configureWithNullConsumerThrowsIllegalArgumentException() {
445+
void configureWithNullConsumerThrowsIllegalArgumentException() {
442446

443447
assertThatIllegalArgumentException()
444448
.isThrownBy(() -> new GenericJackson2JsonRedisSerializer().configure(null))
445449
.withMessage("Consumer used to configure and customize ObjectMapper must not be null")
446450
.withNoCause();
447451
}
448452

453+
@Test
454+
void customSerializeAndDeserializeNullValue() {
455+
456+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(
457+
null,
458+
(mapper, source, type) -> {
459+
if (type.getRawClass() == User.class) {
460+
return mapper.readerWithView(Views.Basic.class).forType(type).readValue(source);
461+
}
462+
return mapper.readValue(source, type);
463+
}, JacksonObjectWriter.create(), new StdSerializer<>(NullValue.class) {
464+
@Override
465+
public void serialize(NullValue nullValue,
466+
JsonGenerator jsonGenerator,
467+
SerializerProvider serializerProvider) throws IOException {
468+
jsonGenerator.writeNull();
469+
}
470+
471+
@Override
472+
public void serializeWithType(NullValue value, JsonGenerator jsonGenerator, SerializerProvider serializers,
473+
TypeSerializer typeSerializer) throws IOException {
474+
475+
serialize(value, jsonGenerator, serializers);
476+
}
477+
});
478+
479+
NullValue nv = BeanUtils.instantiateClass(NullValue.class);
480+
481+
byte[] serializedValue = serializer.serialize(nv);
482+
assertThat(serializedValue).isNotNull();
483+
484+
Object deserializedValue = serializer.deserialize(serializedValue);
485+
assertThat(deserializedValue).isNull();
486+
}
487+
449488
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
450489

451490
NullValue nv = BeanUtils.instantiateClass(NullValue.class);

0 commit comments

Comments
 (0)