Allow configuring custom NullValueSerializer.
Closes #2878 Original pull request: #2905
This commit is contained in:
@@ -134,6 +134,17 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Objec
|
||||
this.mapper.setDefaultTyping(typer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method returning a {@literal Builder} used to construct and configure a {@link GenericJackson2JsonRedisSerializer}.
|
||||
*
|
||||
* @return new {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public static GenericJackson2JsonRedisSerializerBuilder builder(ObjectMapper objectMapper, JacksonObjectReader reader,
|
||||
JacksonObjectWriter writer) {
|
||||
return new GenericJackson2JsonRedisSerializerBuilder(objectMapper, reader, writer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -396,6 +407,69 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Objec
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@literal Builder} for creating a {@link GenericJackson2JsonRedisSerializer}.
|
||||
*
|
||||
* @author Anne Lee
|
||||
* @since 3.3
|
||||
*/
|
||||
public static class GenericJackson2JsonRedisSerializerBuilder {
|
||||
@Nullable
|
||||
private String classPropertyTypeName;
|
||||
private JacksonObjectReader reader;
|
||||
private JacksonObjectWriter writer;
|
||||
private ObjectMapper mapper;
|
||||
@Nullable
|
||||
private StdSerializer<NullValue> nullValueSerializer;
|
||||
|
||||
private GenericJackson2JsonRedisSerializerBuilder(
|
||||
ObjectMapper objectMapper,
|
||||
JacksonObjectReader reader,
|
||||
JacksonObjectWriter writer
|
||||
) {
|
||||
this.mapper = objectMapper;
|
||||
this.reader = reader;
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a classPropertyName.
|
||||
*
|
||||
* @param classPropertyTypeName can be {@literal null}.
|
||||
* @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
|
||||
* @since 3.3
|
||||
*/
|
||||
public GenericJackson2JsonRedisSerializerBuilder classPropertyTypeName(@Nullable String classPropertyTypeName) {
|
||||
this.classPropertyTypeName = classPropertyTypeName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a nullValueSerializer.
|
||||
*
|
||||
* @param nullValueSerializer the {@link StdSerializer} to use for {@link NullValue} serialization. Can be {@literal null}.
|
||||
* @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
|
||||
*/
|
||||
public GenericJackson2JsonRedisSerializerBuilder registerNullValueSerializer(@Nullable StdSerializer<NullValue> nullValueSerializer) {
|
||||
this.nullValueSerializer = nullValueSerializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new instance of {@link GenericJackson2JsonRedisSerializer} with configuration options applied.
|
||||
*
|
||||
* @return new instance of {@link GenericJackson2JsonRedisSerializer}.
|
||||
*/
|
||||
public GenericJackson2JsonRedisSerializer build() {
|
||||
Assert.notNull(this.mapper, "ObjectMapper must not be null");
|
||||
Assert.notNull(this.reader, "Reader must not be null");
|
||||
Assert.notNull(this.writer, "Writer must not be null");
|
||||
|
||||
this.mapper.registerModule(new SimpleModule().addSerializer(this.nullValueSerializer != null ? this.nullValueSerializer : new NullValueSerializer(this.classPropertyTypeName)));
|
||||
return new GenericJackson2JsonRedisSerializer(this.mapper, this.reader, this.writer, this.classPropertyTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom {@link StdTypeResolverBuilder} that considers typing for non-primitive types. Primitives, their wrappers and
|
||||
* primitive arrays do not require type hints. The default {@code DefaultTyping#EVERYTHING} typing does not satisfy
|
||||
|
||||
@@ -40,6 +40,10 @@ import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
@@ -420,7 +424,7 @@ class GenericJackson2JsonRedisSerializerUnitTests {
|
||||
}
|
||||
|
||||
@Test // GH-2601
|
||||
public void internalObjectMapperCustomization() {
|
||||
void internalObjectMapperCustomization() {
|
||||
|
||||
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
|
||||
|
||||
@@ -432,13 +436,13 @@ class GenericJackson2JsonRedisSerializerUnitTests {
|
||||
|
||||
assertThat(serializer.configure(configurer)).isSameAs(serializer);
|
||||
|
||||
verify(mockObjectMapper, times(1)).registerModule(eq(mockModule));
|
||||
verify(mockObjectMapper, times(1)).registerModule(mockModule);
|
||||
verifyNoMoreInteractions(mockObjectMapper);
|
||||
verifyNoInteractions(mockModule);
|
||||
}
|
||||
|
||||
@Test // GH-2601
|
||||
public void configureWithNullConsumerThrowsIllegalArgumentException() {
|
||||
void configureWithNullConsumerThrowsIllegalArgumentException() {
|
||||
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> new GenericJackson2JsonRedisSerializer().configure(null))
|
||||
@@ -446,6 +450,49 @@ class GenericJackson2JsonRedisSerializerUnitTests {
|
||||
.withNoCause();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultSerializeAndDeserializeNullValueWithBuilderClass() {
|
||||
GenericJackson2JsonRedisSerializer serializer = GenericJackson2JsonRedisSerializer.builder(
|
||||
new ObjectMapper().enableDefaultTyping(DefaultTyping.EVERYTHING, As.PROPERTY),
|
||||
JacksonObjectReader.create(), JacksonObjectWriter.create())
|
||||
.classPropertyTypeName(null)
|
||||
.registerNullValueSerializer(null)
|
||||
.build();
|
||||
|
||||
serializeAndDeserializeNullValue(serializer);
|
||||
}
|
||||
|
||||
@Test
|
||||
void customSerializeAndDeserializeNullValueWithBuilderClass() {
|
||||
GenericJackson2JsonRedisSerializer serializer = GenericJackson2JsonRedisSerializer.builder(
|
||||
new ObjectMapper(), JacksonObjectReader.create(), JacksonObjectWriter.create())
|
||||
.classPropertyTypeName(null)
|
||||
.registerNullValueSerializer(new StdSerializer<>(NullValue.class) {
|
||||
@Override
|
||||
public void serialize(NullValue nullValue,
|
||||
JsonGenerator jsonGenerator,
|
||||
SerializerProvider serializerProvider) throws IOException {
|
||||
jsonGenerator.writeNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWithType(NullValue value, JsonGenerator jsonGenerator, SerializerProvider serializers,
|
||||
TypeSerializer typeSerializer) throws IOException {
|
||||
|
||||
serialize(value, jsonGenerator, serializers);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
NullValue nv = BeanUtils.instantiateClass(NullValue.class);
|
||||
|
||||
byte[] serializedValue = serializer.serialize(nv);
|
||||
assertThat(serializedValue).isNotNull();
|
||||
|
||||
Object deserializedValue = serializer.deserialize(serializedValue);
|
||||
assertThat(deserializedValue).isNull();
|
||||
}
|
||||
|
||||
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
|
||||
|
||||
NullValue nv = BeanUtils.instantiateClass(NullValue.class);
|
||||
|
||||
Reference in New Issue
Block a user