Skip to content

Commit 8aaf501

Browse files
committed
Spike on parsed JsonNode reuse.
1 parent 41c512b commit 8aaf501

File tree

3 files changed

+38
-10
lines changed

3 files changed

+38
-10
lines changed

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

+21-7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder;
5252
import com.fasterxml.jackson.databind.module.SimpleModule;
5353
import com.fasterxml.jackson.databind.node.TextNode;
54+
import com.fasterxml.jackson.databind.node.TreeTraversingParser;
5455
import com.fasterxml.jackson.databind.ser.SerializerFactory;
5556
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
5657
import com.fasterxml.jackson.databind.type.TypeFactory;
@@ -306,12 +307,21 @@ public <T> T deserialize(@Nullable byte[] source, Class<T> type) throws Serializ
306307
}
307308

308309
try {
309-
return (T) reader.read(mapper, source, resolveType(source, type));
310+
311+
TypeTuple typeTuple = resolveType(source, type);
312+
try (JsonParser parser = createParser(source, typeTuple)) {
313+
return (T) reader.read(mapper, parser, typeTuple.type());
314+
}
315+
310316
} catch (Exception ex) {
311-
throw new SerializationException("Could not read JSON:%s ".formatted(ex.getMessage()), ex);
317+
throw new SerializationException("Could not read JSON: %s ".formatted(ex.getMessage()), ex);
312318
}
313319
}
314320

321+
private JsonParser createParser(byte[] source, TypeTuple typeTuple) throws IOException {
322+
return typeTuple.node() == null ? mapper.createParser(source) : new TreeTraversingParser(typeTuple.node(), mapper);
323+
}
324+
315325
/**
316326
* Builder method used to configure and customize the internal Jackson {@link ObjectMapper} created by this
317327
* {@link GenericJackson2JsonRedisSerializer} and used to de/serialize {@link Object objects} as {@literal JSON}.
@@ -332,15 +342,19 @@ public GenericJackson2JsonRedisSerializer configure(Consumer<ObjectMapper> objec
332342
return this;
333343
}
334344

335-
protected JavaType resolveType(byte[] source, Class<?> type) throws IOException {
345+
protected TypeTuple resolveType(byte[] source, Class<?> type) throws IOException {
336346

337347
if (!type.equals(Object.class) || !defaultTypingEnabled.get()) {
338-
return typeResolver.constructType(type);
348+
return new TypeTuple(typeResolver.constructType(type), null);
339349
}
340350

341351
return typeResolver.resolveType(source, type);
342352
}
343353

354+
protected record TypeTuple(JavaType type, @Nullable JsonNode node) {
355+
356+
}
357+
344358
/**
345359
* @since 3.0
346360
*/
@@ -361,16 +375,16 @@ protected JavaType constructType(Class<?> type) {
361375
return typeFactory.get().constructType(type);
362376
}
363377

364-
protected JavaType resolveType(byte[] source, Class<?> type) throws IOException {
378+
protected TypeTuple resolveType(byte[] source, Class<?> type) throws IOException {
365379

366380
JsonNode root = readTree(source);
367381
JsonNode jsonNode = root.get(hintName.get());
368382

369383
if (jsonNode instanceof TextNode && jsonNode.asText() != null) {
370-
return typeFactory.get().constructFromCanonical(jsonNode.asText());
384+
return new TypeTuple(typeFactory.get().constructFromCanonical(jsonNode.asText()), root);
371385
}
372386

373-
return constructType(type);
387+
return new TypeTuple(constructType(type), root);
374388
}
375389

376390
/**

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public T deserialize(@Nullable byte[] bytes) throws SerializationException {
166166
return null;
167167
}
168168
try {
169-
return (T) this.reader.read(this.mapper, bytes, javaType);
169+
return (T) this.reader.read(this.mapper, this.mapper.createParser(bytes), javaType);
170170
} catch (Exception ex) {
171171
throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
172172
}

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

+16-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.io.IOException;
1919
import java.io.InputStream;
2020

21+
import com.fasterxml.jackson.core.JsonParser;
2122
import com.fasterxml.jackson.databind.JavaType;
2223
import com.fasterxml.jackson.databind.ObjectMapper;
2324

@@ -43,15 +44,28 @@ public interface JacksonObjectReader {
4344
* @return the deserialized Java object.
4445
* @throws IOException if an I/O error or JSON deserialization error occurs.
4546
*/
46-
Object read(ObjectMapper mapper, byte[] source, JavaType type) throws IOException;
47+
default Object read(ObjectMapper mapper, byte[] source, JavaType type) throws IOException {
48+
return read(mapper, mapper.createParser(source), type);
49+
}
50+
51+
/**
52+
* Read an object graph from the given root JSON into a Java object considering the {@link JavaType}.
53+
*
54+
* @param mapper the object mapper to use.
55+
* @param parser the JSON parser to use.
56+
* @param type the Java target type
57+
* @return the deserialized Java object.
58+
* @throws IOException if an I/O error or JSON deserialization error occurs.
59+
*/
60+
Object read(ObjectMapper mapper, JsonParser parser, JavaType type) throws IOException;
4761

4862
/**
4963
* Create a default {@link JacksonObjectReader} delegating to {@link ObjectMapper#readValue(InputStream, JavaType)}.
5064
*
5165
* @return the default {@link JacksonObjectReader}.
5266
*/
5367
static JacksonObjectReader create() {
54-
return (mapper, source, type) -> mapper.readValue(source, 0, source.length, type);
68+
return ObjectMapper::readValue;
5569
}
5670

5771
}

0 commit comments

Comments
 (0)