Skip to content

Commit 634fd84

Browse files
committed
Better or just different?
1 parent b366c8c commit 634fd84

File tree

1 file changed

+44
-46
lines changed

1 file changed

+44
-46
lines changed

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

+44-46
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.io.IOException;
1919
import java.util.Collections;
20+
import java.util.Map;
2021
import java.util.function.Supplier;
2122

2223
import org.springframework.cache.support.NullValue;
@@ -29,15 +30,12 @@
2930
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
3031
import com.fasterxml.jackson.core.JsonGenerator;
3132
import com.fasterxml.jackson.databind.JavaType;
32-
import com.fasterxml.jackson.databind.JsonNode;
3333
import com.fasterxml.jackson.databind.ObjectMapper;
3434
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
35-
import com.fasterxml.jackson.databind.ObjectReader;
3635
import com.fasterxml.jackson.databind.SerializerProvider;
3736
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
3837
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
3938
import com.fasterxml.jackson.databind.module.SimpleModule;
40-
import com.fasterxml.jackson.databind.node.TextNode;
4139
import com.fasterxml.jackson.databind.ser.SerializerFactory;
4240
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
4341
import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -55,37 +53,16 @@
5553
*/
5654
public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Object> {
5755

58-
private ObjectMapper mapper;
56+
private final ObjectMapper mapper;
5957

6058
private final JacksonObjectReader reader;
6159

6260
private final JacksonObjectWriter writer;
6361

64-
private boolean internalReader = false;
62+
private final Lazy<Boolean> defaultTypingEnabled;
6563

6664
private final TypeResolver typeResolver;
6765

68-
private Lazy<Boolean> defaultTypingEnabled = Lazy
69-
.of(() -> mapper.getSerializationConfig().getDefaultTyper(null) != null);
70-
71-
private Lazy<String> typeHintPropertyName;
72-
73-
{
74-
typeHintPropertyName = Lazy.of(() -> {
75-
if (defaultTypingEnabled.get()) {
76-
return null;
77-
}
78-
79-
return mapper.getDeserializationConfig().getDefaultTyper(null)
80-
.buildTypeDeserializer(mapper.getDeserializationConfig(), mapper.getTypeFactory().constructType(Object.class),
81-
Collections.emptyList())
82-
.getPropertyName();
83-
84-
}).or("@class");
85-
86-
typeResolver = new TypeResolver(Lazy.of(() -> mapper.getTypeFactory()), typeHintPropertyName);
87-
}
88-
8966
/**
9067
* Creates {@link GenericJackson2JsonRedisSerializer} and configures {@link ObjectMapper} for default typing.
9168
*/
@@ -104,7 +81,6 @@ public GenericJackson2JsonRedisSerializer() {
10481
*/
10582
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {
10683
this(classPropertyTypeName, JacksonObjectReader.create(), JacksonObjectWriter.create());
107-
this.internalReader = true;
10884
}
10985

11086
/**
@@ -122,7 +98,7 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
12298
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName, JacksonObjectReader reader,
12399
JacksonObjectWriter writer) {
124100

125-
this(new ObjectMapper(), reader, writer);
101+
this(new ObjectMapper(), reader, writer, classPropertyTypeName);
126102

127103
// simply setting {@code mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)} does not help here since we need
128104
// the type hint embedded for deserialization using the default typing feature.
@@ -134,10 +110,6 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
134110
} else {
135111
mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), DefaultTyping.EVERYTHING, As.PROPERTY);
136112
}
137-
138-
if (classPropertyTypeName != null) {
139-
typeHintPropertyName = Lazy.of(classPropertyTypeName);
140-
}
141113
}
142114

143115
/**
@@ -149,7 +121,6 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
149121
*/
150122
public GenericJackson2JsonRedisSerializer(ObjectMapper mapper) {
151123
this(mapper, JacksonObjectReader.create(), JacksonObjectWriter.create());
152-
this.internalReader = true;
153124
}
154125

155126
/**
@@ -164,6 +135,11 @@ public GenericJackson2JsonRedisSerializer(ObjectMapper mapper) {
164135
*/
165136
public GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectReader reader,
166137
JacksonObjectWriter writer) {
138+
this(mapper, reader, writer, null);
139+
}
140+
141+
private GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectReader reader,
142+
JacksonObjectWriter writer, @Nullable String typeHintPropertyName) {
167143

168144
Assert.notNull(mapper, "ObjectMapper must not be null!");
169145
Assert.notNull(reader, "Reader must not be null!");
@@ -172,6 +148,29 @@ public GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectRead
172148
this.mapper = mapper;
173149
this.reader = reader;
174150
this.writer = writer;
151+
152+
this.defaultTypingEnabled = Lazy.of(() -> mapper.getSerializationConfig().getDefaultTyper(null) != null);
153+
154+
Supplier<String> typeHintPropertyNameSupplier;
155+
156+
if (typeHintPropertyName == null) {
157+
158+
typeHintPropertyNameSupplier = Lazy.of(() -> {
159+
if (defaultTypingEnabled.get()) {
160+
return null;
161+
}
162+
163+
return mapper.getDeserializationConfig().getDefaultTyper(null)
164+
.buildTypeDeserializer(mapper.getDeserializationConfig(),
165+
mapper.getTypeFactory().constructType(Object.class), Collections.emptyList())
166+
.getPropertyName();
167+
168+
}).or("@class");
169+
} else {
170+
typeHintPropertyNameSupplier = () -> typeHintPropertyName;
171+
}
172+
173+
this.typeResolver = new TypeResolver(Lazy.of(mapper::getTypeFactory), typeHintPropertyNameSupplier);
175174
}
176175

177176
/**
@@ -233,21 +232,22 @@ public <T> T deserialize(@Nullable byte[] source, Class<T> type) throws Serializ
233232
}
234233
}
235234

236-
protected JavaType resolveType(byte[] source, Class<?> type) {
235+
protected JavaType resolveType(byte[] source, Class<?> type) throws IOException {
237236

238-
if (internalReader || !type.equals(Object.class) || !defaultTypingEnabled.get()) {
237+
if (!type.equals(Object.class) || !defaultTypingEnabled.get()) {
239238
return typeResolver.constructType(type);
240239
}
241240

242241
return typeResolver.resolveType(source, type);
243242
}
244243

245-
private static class TypeResolver {
244+
static class TypeResolver {
246245

247-
private final ObjectReader objectReader = new ObjectMapper().reader();
246+
// need a separate instance to bypass class hint checks
247+
private final ObjectMapper mapper = new ObjectMapper();
248248

249249
private final Supplier<TypeFactory> typeFactory;
250-
private Supplier<String> hintName;
250+
private final Supplier<String> hintName;
251251

252252
public TypeResolver(Supplier<TypeFactory> typeFactory, Supplier<String> hintName) {
253253

@@ -259,15 +259,13 @@ protected JavaType constructType(Class<?> type) {
259259
return typeFactory.get().constructType(type);
260260
}
261261

262-
protected JavaType resolveType(byte[] source, Class<?> type) {
262+
protected JavaType resolveType(byte[] source, Class<?> type) throws IOException {
263263

264-
try {
265-
TextNode typeName = (TextNode) objectReader.readValue(source, JsonNode.class).get(hintName.get());
266-
if (typeName != null) {
267-
return typeFactory.get().constructFromCanonical(typeName.textValue());
268-
}
269-
} catch (IOException e) {
270-
// TODO: logging?
264+
Map<?, ?> map = mapper.readValue(source, Map.class);
265+
Object typeName = map.get(hintName.get());
266+
267+
if (typeName != null) {
268+
return typeFactory.get().constructFromCanonical(typeName.toString());
271269
}
272270

273271
return constructType(type);

0 commit comments

Comments
 (0)