Skip to content

Commit 048b21a

Browse files
committed
feat: add custom NullValueSerializer initializer
1 parent 3ab09fb commit 048b21a

File tree

2 files changed

+67
-2
lines changed

2 files changed

+67
-2
lines changed

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,38 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
134134
this.mapper.setDefaultTyping(typer);
135135
}
136136

137+
/**
138+
* Creates {@link GenericJackson2JsonRedisSerializer} initialized with an {@link ObjectMapper} configured for default
139+
* typing using the given {@link String name} along with the given, required {@link JacksonObjectReader} and
140+
* {@link JacksonObjectWriter} used to read/write {@link Object Objects} de/serialized as JSON,
141+
* optionally customized {@link NullValueSerializer}.
142+
* <p>
143+
* In case {@link String name} is {@literal empty} or {@literal null}, then {@link JsonTypeInfo.Id#CLASS} will be
144+
* used.
145+
* <p>
146+
* In case {@link StdSerializer} is {@literal null}, then a default {@link NullValueSerializer} will be registered.
147+
*
148+
* @param classPropertyTypeName {@link String name} of the JSON property holding type information; can be
149+
* {@literal null}.
150+
* @param reader {@link JacksonObjectReader} function to read objects using {@link ObjectMapper}.
151+
* @param writer {@link JacksonObjectWriter} function to write objects using {@link ObjectMapper}.
152+
* @param nullValueSerializer {@link StdSerializer} to serialize {@link NullValue} instances.
153+
* @see ObjectMapper#activateDefaultTypingAsProperty(PolymorphicTypeValidator, DefaultTyping, String)
154+
* @see ObjectMapper#activateDefaultTyping(PolymorphicTypeValidator, DefaultTyping, As)
155+
* @since 3.3
156+
*/
157+
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName, JacksonObjectReader reader,
158+
JacksonObjectWriter writer, @Nullable StdSerializer<NullValue> nullValueSerializer) {
159+
160+
this(classPropertyTypeName, reader, writer);
161+
162+
if (nullValueSerializer == null) {
163+
registerNullValueSerializer(this.mapper, classPropertyTypeName);
164+
} else {
165+
registerCustomNullValueSerializer(nullValueSerializer);
166+
}
167+
}
168+
137169
/**
138170
* Setting a custom-configured {@link ObjectMapper} is one way to take further control of the JSON serialization
139171
* process. For example, an extended {@link SerializerFactory} can be configured that provides custom serializers for
@@ -231,6 +263,10 @@ public static void registerNullValueSerializer(ObjectMapper objectMapper, @Nulla
231263
objectMapper.registerModule(new SimpleModule().addSerializer(new NullValueSerializer(classPropertyTypeName)));
232264
}
233265

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

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

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
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.ser.std.StdSerializer;
4346
import org.junit.jupiter.api.Test;
4447
import org.mockito.Mockito;
4548

@@ -420,7 +423,7 @@ void deserializesJavaTimeFrimBytes() {
420423
}
421424

422425
@Test // GH-2601
423-
public void internalObjectMapperCustomization() {
426+
void internalObjectMapperCustomization() {
424427

425428
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
426429

@@ -438,14 +441,40 @@ public void internalObjectMapperCustomization() {
438441
}
439442

440443
@Test // GH-2601
441-
public void configureWithNullConsumerThrowsIllegalArgumentException() {
444+
void configureWithNullConsumerThrowsIllegalArgumentException() {
442445

443446
assertThatIllegalArgumentException()
444447
.isThrownBy(() -> new GenericJackson2JsonRedisSerializer().configure(null))
445448
.withMessage("Consumer used to configure and customize ObjectMapper must not be null")
446449
.withNoCause();
447450
}
448451

452+
@Test
453+
void customSerializeAndDeserializeNullValue() {
454+
455+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer(
456+
null,
457+
(mapper, source, type) -> {
458+
if (type.getRawClass() == User.class) {
459+
return mapper.readerWithView(Views.Basic.class).forType(type).readValue(source);
460+
}
461+
return mapper.readValue(source, type);
462+
}, JacksonObjectWriter.create(), new StdSerializer<>(NullValue.class) {
463+
@Override
464+
public void serialize(NullValue nullValue,
465+
JsonGenerator jsonGenerator,
466+
SerializerProvider serializerProvider) throws IOException {
467+
jsonGenerator.writeNull();
468+
}
469+
});
470+
471+
byte[] serializedValue = serializer.serialize(null);
472+
assertThat(serializedValue).isNotNull();
473+
474+
Object deserializedValue = serializer.deserialize(serializedValue);
475+
assertThat(deserializedValue).isNull();
476+
}
477+
449478
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
450479

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

0 commit comments

Comments
 (0)