Skip to content

Commit d14cca9

Browse files
committed
Polishing.
Introduce single private constructor to accept all arguments.
1 parent b366c8c commit d14cca9

File tree

1 file changed

+43
-44
lines changed

1 file changed

+43
-44
lines changed

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

+43-44
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
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;
@@ -55,37 +54,16 @@
5554
*/
5655
public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Object> {
5756

58-
private ObjectMapper mapper;
57+
private final ObjectMapper mapper;
5958

6059
private final JacksonObjectReader reader;
6160

6261
private final JacksonObjectWriter writer;
6362

64-
private boolean internalReader = false;
63+
private final Lazy<Boolean> defaultTypingEnabled;
6564

6665
private final TypeResolver typeResolver;
6766

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-
8967
/**
9068
* Creates {@link GenericJackson2JsonRedisSerializer} and configures {@link ObjectMapper} for default typing.
9169
*/
@@ -104,7 +82,6 @@ public GenericJackson2JsonRedisSerializer() {
10482
*/
10583
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {
10684
this(classPropertyTypeName, JacksonObjectReader.create(), JacksonObjectWriter.create());
107-
this.internalReader = true;
10885
}
10986

11087
/**
@@ -122,7 +99,7 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
12299
public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName, JacksonObjectReader reader,
123100
JacksonObjectWriter writer) {
124101

125-
this(new ObjectMapper(), reader, writer);
102+
this(new ObjectMapper(), reader, writer, classPropertyTypeName);
126103

127104
// simply setting {@code mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)} does not help here since we need
128105
// the type hint embedded for deserialization using the default typing feature.
@@ -134,10 +111,6 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
134111
} else {
135112
mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), DefaultTyping.EVERYTHING, As.PROPERTY);
136113
}
137-
138-
if (classPropertyTypeName != null) {
139-
typeHintPropertyName = Lazy.of(classPropertyTypeName);
140-
}
141114
}
142115

143116
/**
@@ -149,7 +122,6 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
149122
*/
150123
public GenericJackson2JsonRedisSerializer(ObjectMapper mapper) {
151124
this(mapper, JacksonObjectReader.create(), JacksonObjectWriter.create());
152-
this.internalReader = true;
153125
}
154126

155127
/**
@@ -164,6 +136,11 @@ public GenericJackson2JsonRedisSerializer(ObjectMapper mapper) {
164136
*/
165137
public GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectReader reader,
166138
JacksonObjectWriter writer) {
139+
this(mapper, reader, writer, null);
140+
}
141+
142+
private GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectReader reader,
143+
JacksonObjectWriter writer, @Nullable String typeHintPropertyName) {
167144

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

177177
/**
@@ -233,21 +233,22 @@ public <T> T deserialize(@Nullable byte[] source, Class<T> type) throws Serializ
233233
}
234234
}
235235

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

238-
if (internalReader || !type.equals(Object.class) || !defaultTypingEnabled.get()) {
238+
if (!type.equals(Object.class) || !defaultTypingEnabled.get()) {
239239
return typeResolver.constructType(type);
240240
}
241241

242242
return typeResolver.resolveType(source, type);
243243
}
244244

245-
private static class TypeResolver {
245+
static class TypeResolver {
246246

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

249250
private final Supplier<TypeFactory> typeFactory;
250-
private Supplier<String> hintName;
251+
private final Supplier<String> hintName;
251252

252253
public TypeResolver(Supplier<TypeFactory> typeFactory, Supplier<String> hintName) {
253254

@@ -259,15 +260,13 @@ protected JavaType constructType(Class<?> type) {
259260
return typeFactory.get().constructType(type);
260261
}
261262

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

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?
265+
JsonNode root = mapper.readTree(source);
266+
JsonNode jsonNode = root.get(hintName.get());
267+
268+
if (jsonNode instanceof TextNode && jsonNode.asText() != null) {
269+
return typeFactory.get().constructFromCanonical(jsonNode.asText());
271270
}
272271

273272
return constructType(type);

0 commit comments

Comments
 (0)