Allow users to customize the internal ObjectMapper created by GenericJackson2JsonRedisSerializer.

We now allow the internally created Jackson ObjectMapper to be customized and further configured after construction of the GenericJackson2JsonRedisSerializer when a user does not explicitly provide a custom ObjectMapper during construction. Even when providing a custom ObjectMapper, not all configuration applied by the GenericJackson2JsonRedisSerialzier (such as (standard) type resolution) to the internal ObjectMapper would get applied to the user-provided ObjectMapper as well.

Closes #2601
This commit is contained in:
John Blum
2023-06-14 13:41:19 -07:00
parent f1492e1790
commit f3de2d51dc
2 changed files with 71 additions and 4 deletions

View File

@@ -18,6 +18,7 @@ package org.springframework.data.redis.serializer;
import java.io.IOException;
import java.io.Serial;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.springframework.cache.support.NullValue;
@@ -196,12 +197,22 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Objec
return typeHintPropertyName != null ? () -> typeHintPropertyName
: Lazy.of(() -> defaultTypingEnabled.get() ? null
: mapper.getDeserializationConfig().getDefaultTyper(null)
.buildTypeDeserializer(mapper.getDeserializationConfig(),
mapper.getTypeFactory().constructType(Object.class), Collections.emptyList())
.buildTypeDeserializer(mapper.getDeserializationConfig(),
mapper.getTypeFactory().constructType(Object.class), Collections.emptyList())
.getPropertyName())
.or("@class");
}
/**
* Gets the configured {@link ObjectMapper} used internally by this {@link GenericJackson2JsonRedisSerializer}
* to de/serialize {@link Object objects} as {@literal JSON}.
*
* @return the configured {@link ObjectMapper}.
*/
protected ObjectMapper getObjectMapper() {
return this.mapper;
}
@Override
public byte[] serialize(@Nullable Object source) throws SerializationException {
@@ -248,11 +259,33 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Objec
try {
return (T) reader.read(mapper, source, resolveType(source, type));
} catch (Exception ex) {
throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
} catch (Exception cause) {
String message = String.format("Could not read JSON:%s ", cause.getMessage());
throw new SerializationException(message, cause);
}
}
/**
* Builder method used to configure and customize the internal Jackson {@link ObjectMapper} created by
* this {@link GenericJackson2JsonRedisSerializer} and used to de/serialize {@link Object objects}
* as {@literal JSON}.
*
* @param objectMapperConfigurer {@link Consumer} used to configure and customize the internal {@link ObjectMapper};
* must not be {@literal null}.
* @return this {@link GenericJackson2JsonRedisSerializer}.
* @throws IllegalArgumentException if the {@link Consumer} used to configure and customize
* the internal {@link ObjectMapper} is {@literal null}.
*/
public GenericJackson2JsonRedisSerializer configure(Consumer<ObjectMapper> objectMapperConfigurer) {
Assert.notNull(objectMapperConfigurer,
"Consumer used to configure and customize ObjectMapper must not be null");
objectMapperConfigurer.accept(getObjectMapper());
return this;
}
protected JavaType resolveType(byte[] source, Class<?> type) throws IOException {
if (!type.equals(Object.class) || !defaultTypingEnabled.get()) {