Skip to content

Commit 341f8d3

Browse files
authored
Add a way to configure DeserializerCache Jackson uses (#4101)
1 parent c0f01a5 commit 341f8d3

File tree

7 files changed

+389
-23
lines changed

7 files changed

+389
-23
lines changed

src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java

+25-15
Original file line numberDiff line numberDiff line change
@@ -161,21 +161,11 @@ public abstract class DeserializationContext
161161
/**********************************************************
162162
*/
163163

164-
protected DeserializationContext(DeserializerFactory df) {
165-
this(df, null);
166-
}
167-
168164
protected DeserializationContext(DeserializerFactory df,
169165
DeserializerCache cache)
170166
{
171-
if (df == null) {
172-
throw new NullPointerException("Cannot pass null DeserializerFactory");
173-
}
174-
_factory = df;
175-
if (cache == null) {
176-
cache = new DeserializerCache();
177-
}
178-
_cache = cache;
167+
_factory = Objects.requireNonNull(df);
168+
_cache = Objects.requireNonNull(cache);
179169
_featureFlags = 0;
180170
_readCapabilities = null;
181171
_config = null;
@@ -199,6 +189,24 @@ protected DeserializationContext(DeserializationContext src,
199189
_attributes = src._attributes;
200190
}
201191

192+
/**
193+
* @since 2.16
194+
*/
195+
protected DeserializationContext(DeserializationContext src,
196+
DeserializerCache cache)
197+
{
198+
_cache = cache;
199+
_factory = src._factory;
200+
201+
_config = src._config;
202+
_featureFlags = src._featureFlags;
203+
_readCapabilities = src._readCapabilities;
204+
_view = src._view;
205+
_parser = src._parser;
206+
_injectableValues = src._injectableValues;
207+
_attributes = src._attributes;
208+
}
209+
202210
/**
203211
* Constructor used for creating actual per-call instances.
204212
*/
@@ -243,17 +251,19 @@ protected DeserializationContext(DeserializationContext src,
243251
}
244252

245253
/**
246-
* Copy-constructor for use with <code>copy()</code> by {@link ObjectMapper#copy()}
254+
* Copy-constructor for use with <code>copy()</code> by {@link ObjectMapper#copy()}.
255+
* Only called on blueprint objects.
247256
*/
248257
protected DeserializationContext(DeserializationContext src) {
249-
_cache = new DeserializerCache();
258+
_cache = src._cache.emptyCopy();
250259
_factory = src._factory;
251260

252261
_config = src._config;
253262
_featureFlags = src._featureFlags;
254263
_readCapabilities = src._readCapabilities;
255264
_view = src._view;
256-
_injectableValues = null;
265+
_injectableValues = src._injectableValues;
266+
_attributes = null;
257267
}
258268

259269
/*

src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java

+1
Original file line numberDiff line numberDiff line change
@@ -2282,6 +2282,7 @@ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) {
22822282
_assertNotNull("cacheProvider", cacheProvider);
22832283
_deserializationConfig = _deserializationConfig.with(cacheProvider);
22842284
_serializationConfig = _serializationConfig.with(cacheProvider);
2285+
_deserializationContext = _deserializationContext.withCaches(cacheProvider);
22852286
return this;
22862287
}
22872288

src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package com.fasterxml.jackson.databind.cfg;
22

3+
import com.fasterxml.jackson.databind.DeserializationConfig;
4+
import com.fasterxml.jackson.databind.JavaType;
5+
import com.fasterxml.jackson.databind.JsonDeserializer;
6+
import com.fasterxml.jackson.databind.deser.DeserializerCache;
7+
import com.fasterxml.jackson.databind.util.LookupCache;
8+
39
/**
410
* Interface that defines API Jackson uses for constructing various internal
511
* caches. This allows configuring custom caches and cache configurations.
@@ -11,5 +17,11 @@
1117
public interface CacheProvider
1218
extends java.io.Serializable
1319
{
14-
// !!! TODO: add methods
20+
/**
21+
* Method to provide a {@link LookupCache} instance for constructing {@link DeserializerCache}.
22+
*
23+
* @return {@link LookupCache} instance for constructing {@link DeserializerCache}.
24+
*/
25+
LookupCache<JavaType, JsonDeserializer<Object>> forDeserializerCache(DeserializationConfig config);
26+
1527
}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,142 @@
11
package com.fasterxml.jackson.databind.cfg;
22

3+
import com.fasterxml.jackson.databind.DeserializationConfig;
4+
import com.fasterxml.jackson.databind.JavaType;
5+
import com.fasterxml.jackson.databind.JsonDeserializer;
6+
import com.fasterxml.jackson.databind.deser.DeserializerCache;
7+
import com.fasterxml.jackson.databind.util.LRUMap;
8+
import com.fasterxml.jackson.databind.util.LookupCache;
9+
310
/**
4-
* Default implementation of {@link CacheProvider}.
5-
*
11+
* The default implementation of {@link CacheProvider}.
12+
* Configuration is builder-based via {@link DefaultCacheProvider.Builder}.
13+
* <p>
14+
* Users can either use this class or create their own {@link CacheProvider} implementation.
15+
*
616
* @since 2.16
717
*/
818
public class DefaultCacheProvider
919
implements CacheProvider
1020
{
1121
private static final long serialVersionUID = 1L;
1222

13-
public static DefaultCacheProvider defaultInstance() {
14-
return new DefaultCacheProvider();
15-
}
23+
private final static DefaultCacheProvider DEFAULT
24+
= new DefaultCacheProvider(DeserializerCache.DEFAULT_MAX_CACHE_SIZE);
25+
26+
/**
27+
* Maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}.
28+
*
29+
* @see Builder#maxDeserializerCacheSize(int)
30+
*/
31+
protected final int _maxDeserializerCacheSize;
1632

17-
// To implement!
33+
/*
34+
/**********************************************************************
35+
/* Life cycle
36+
/**********************************************************************
37+
*/
38+
39+
protected DefaultCacheProvider(int deserializerCache)
40+
{
41+
_maxDeserializerCacheSize = deserializerCache;
42+
}
43+
44+
/*
45+
/**********************************************************************
46+
/* Defaults
47+
/**********************************************************************
48+
*/
49+
50+
/**
51+
* @return Default {@link DefaultCacheProvider} instance using default configuration values.
52+
*/
53+
public static CacheProvider defaultInstance() {
54+
return DEFAULT;
55+
}
56+
57+
/*
58+
/**********************************************************
59+
/* API implementation
60+
/**********************************************************
61+
*/
62+
63+
/**
64+
* Method to provide a {@link LookupCache} instance for constructing {@link DeserializerCache}.
65+
* Implementation should match {@link DeserializerCache#DeserializerCache(int)}.
66+
*
67+
* @return {@link LookupCache} instance for constructing {@link DeserializerCache}.
68+
*/
69+
@Override
70+
public LookupCache<JavaType, JsonDeserializer<Object>> forDeserializerCache(DeserializationConfig config) {
71+
return _buildCache(_maxDeserializerCacheSize);
72+
}
1873

74+
/*
75+
/**********************************************************
76+
/* Overridable factory methods
77+
/**********************************************************
78+
*/
79+
80+
protected <K,V> LookupCache<K,V> _buildCache(int maxSize)
81+
{
82+
// Use 1/4 of maximum size (but at most 64) for initial size
83+
final int initialSize = Math.min(64, maxSize >> 2);
84+
return new LRUMap<>(initialSize, maxSize);
85+
}
86+
87+
/*
88+
/**********************************************************
89+
/* Builder Config
90+
/**********************************************************
91+
*/
92+
93+
/**
94+
* @return {@link Builder} instance for configuration.
95+
*/
96+
public static DefaultCacheProvider.Builder builder() {
97+
return new Builder();
98+
}
99+
100+
/**
101+
* Builder offering fluent factory methods to configure {@link DefaultCacheProvider}, keeping it immutable.
102+
*/
103+
public static class Builder {
104+
105+
/**
106+
* Maximum Size of the {@link LookupCache} instance created by {@link #forDeserializerCache(DeserializationConfig)}.
107+
* Corresponds to {@link DefaultCacheProvider#_maxDeserializerCacheSize}.
108+
*/
109+
private int _maxDeserializerCacheSize;
110+
111+
Builder() { }
112+
113+
/**
114+
* Define the maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}.
115+
* The cache is instantiated as:
116+
* <pre>
117+
* return new LRUMap<>(Math.min(64, maxSize >> 2), maxSize);
118+
* </pre>
119+
*
120+
* @param maxDeserializerCacheSize Size for the {@link LookupCache} to use within {@link DeserializerCache}
121+
* @return this builder
122+
* @throws IllegalArgumentException if {@code maxDeserializerCacheSize} is negative
123+
* @since 2.16
124+
*/
125+
public Builder maxDeserializerCacheSize(int maxDeserializerCacheSize) {
126+
if (maxDeserializerCacheSize < 0) {
127+
throw new IllegalArgumentException("Cannot set maxDeserializerCacheSize to a negative value");
128+
}
129+
_maxDeserializerCacheSize = maxDeserializerCacheSize;
130+
return this;
131+
}
132+
133+
/**
134+
* Constructs a {@link DefaultCacheProvider} with the provided configuration values, using defaults where not specified.
135+
*
136+
* @return A {@link DefaultCacheProvider} instance with the specified configuration
137+
*/
138+
public DefaultCacheProvider build() {
139+
return new DefaultCacheProvider(_maxDeserializerCacheSize);
140+
}
141+
}
19142
}

src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java

+34-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.fasterxml.jackson.core.JsonParser;
1212
import com.fasterxml.jackson.core.JsonToken;
1313
import com.fasterxml.jackson.databind.*;
14+
import com.fasterxml.jackson.databind.cfg.CacheProvider;
1415
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
1516
import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
1617
import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring;
@@ -62,6 +63,16 @@ protected DefaultDeserializationContext(DefaultDeserializationContext src,
6263
}
6364

6465
/**
66+
* @since 2.16
67+
*/
68+
protected DefaultDeserializationContext(DefaultDeserializationContext src,
69+
DeserializerCache cache) {
70+
super(src, cache);
71+
}
72+
73+
/**
74+
* Copy-constructor
75+
*
6576
* @since 2.4.4
6677
*/
6778
protected DefaultDeserializationContext(DefaultDeserializationContext src) {
@@ -296,6 +307,13 @@ public final KeyDeserializer keyDeserializerInstance(Annotated ann, Object deser
296307
*/
297308
public abstract DefaultDeserializationContext with(DeserializerFactory factory);
298309

310+
/**
311+
* Fluent factory method used for constructing a new instance with cache instances provided by {@link CacheProvider}.
312+
*
313+
* @since 2.16
314+
*/
315+
public abstract DefaultDeserializationContext withCaches(CacheProvider cacheProvider);
316+
299317
/**
300318
* Method called to create actual usable per-deserialization
301319
* context instance.
@@ -384,7 +402,9 @@ public final static class Impl extends DefaultDeserializationContext
384402
* {@link DeserializerCache}, given factory.
385403
*/
386404
public Impl(DeserializerFactory df) {
387-
super(df, null);
405+
// 04-Sep-2023, tatu: Not ideal (wrt not going via CacheProvider) but
406+
// has to do for backwards compatibility:
407+
super(df, new DeserializerCache());
388408
}
389409

390410
private Impl(Impl src,
@@ -402,6 +422,13 @@ private Impl(Impl src, DeserializationConfig config) {
402422
super(src, config);
403423
}
404424

425+
/**
426+
* @since 2.16
427+
*/
428+
private Impl(Impl src, DeserializerCache deserializerCache) {
429+
super(src, deserializerCache);
430+
}
431+
405432
@Override
406433
public DefaultDeserializationContext copy() {
407434
ClassUtil.verifyMustOverride(Impl.class, this, "copy");
@@ -424,5 +451,11 @@ public DefaultDeserializationContext createDummyInstance(DeserializationConfig c
424451
public DefaultDeserializationContext with(DeserializerFactory factory) {
425452
return new Impl(this, factory);
426453
}
454+
455+
@Override // Since 2.16
456+
public DefaultDeserializationContext withCaches(CacheProvider cacheProvider) {
457+
return new Impl(this,
458+
new DeserializerCache(cacheProvider.forDeserializerCache(_config)));
459+
}
427460
}
428461
}

src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java

+7
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ public DeserializerCache(LookupCache<JavaType, JsonDeserializer<Object>> cache)
7373
_cachedDeserializers = cache;
7474
}
7575

76+
/**
77+
* @since 2.16
78+
*/
79+
public DeserializerCache emptyCopy() {
80+
return new DeserializerCache(_cachedDeserializers.emptyCopy());
81+
}
82+
7683
/*
7784
/**********************************************************
7885
/* JDK serialization handling

0 commit comments

Comments
 (0)