From b1a1519502510bf0fa91ca4e3248bf6f9c0b6131 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 29 Aug 2023 08:12:34 +0900 Subject: [PATCH 01/53] First draft --- .../jackson/databind/CacheProvider.java | 55 ++++++++++++++++++ .../databind/DeserializationConfig.java | 27 +++++++++ .../databind/DeserializationContext.java | 4 +- .../jackson/databind/ObjectMapper.java | 13 +++++ .../jackson/databind/cfg/MapperBuilder.java | 7 +++ .../databind/deser/DeserializerCache.java | 21 ++++++- .../databind/cfg/CacheProviderTest.java | 57 +++++++++++++++++++ 7 files changed, 179 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/fasterxml/jackson/databind/CacheProvider.java create mode 100644 src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java diff --git a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java new file mode 100644 index 0000000000..e1771dd47a --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java @@ -0,0 +1,55 @@ +package com.fasterxml.jackson.databind; + +import com.fasterxml.jackson.databind.util.LookupCache; + +public class CacheProvider { + + protected LookupCache> _typeFactoryCache; + + protected CacheProvider() { + } + + protected CacheProvider forTypeFactory(LookupCache> cache) { + _typeFactoryCache = cache; + return this; + } + + /* + /********************************************************** + /* Builder Initialization + /********************************************************** + */ + + public static CacheProvider.Builder builder() { + return new Builder(new CacheProvider()); + } + + public LookupCache> provideForDeserializerCache() { + return _typeFactoryCache; + } + + public static class Builder { + + protected final CacheProvider cacheProvider; + + public Builder(CacheProvider cacheProvider) { + this.cacheProvider = cacheProvider; + } + + public CacheProvider build() { + return cacheProvider; + } + + + /* + /********************************************************** + /* Configuration using Builder + /********************************************************** + */ + + public Builder withTypeFactoryCache(LookupCache> cache) { + cacheProvider._typeFactoryCache = cache; + return this; + } + } +} diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index b16183776a..db373a61d1 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -6,11 +6,13 @@ import com.fasterxml.jackson.core.json.JsonReadFeature; import com.fasterxml.jackson.databind.cfg.*; import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler; +import com.fasterxml.jackson.databind.deser.DeserializerCache; import com.fasterxml.jackson.databind.introspect.*; import com.fasterxml.jackson.databind.jsontype.*; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.type.LogicalType; import com.fasterxml.jackson.databind.util.LinkedNode; +import com.fasterxml.jackson.databind.util.LookupCache; import com.fasterxml.jackson.databind.util.RootNameLookup; /** @@ -100,6 +102,8 @@ public final class DeserializationConfig * @since 2.7 */ protected final int _formatReadFeaturesToChange; + + protected CacheProvider _cacheProvider; /* /********************************************************** @@ -325,6 +329,20 @@ protected DeserializationConfig(DeserializationConfig src, _formatReadFeaturesToChange = src._formatReadFeaturesToChange; } + public DeserializationConfig(DeserializationConfig src, CacheProvider cacheProvider) { + super(src); + _deserFeatures = src._deserFeatures; + _problemHandlers = src._problemHandlers; + _nodeFactory = src._nodeFactory; + _coercionConfigs = src._coercionConfigs; + _ctorDetector = src._ctorDetector; + _parserFeatures = src._parserFeatures; + _parserFeaturesToChange = src._parserFeaturesToChange; + _formatReadFeatures = src._formatReadFeatures; + _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = cacheProvider; + } + // for unit tests only: protected BaseSettings getBaseSettings() { return _base; } @@ -921,6 +939,10 @@ public ConstructorDetector getConstructorDetector() { } return _ctorDetector; } + + public CacheProvider cacheProvider() { + return _cacheProvider; + } /* /********************************************************** @@ -1046,4 +1068,9 @@ public CoercionAction findCoercionFromBlankString(LogicalType targetType, return _coercionConfigs.findCoercionFromBlankString(this, targetType, targetClass, actionIfBlankNotAllowed); } + + public DeserializationConfig withCacheProvider(CacheProvider cacheProvider) { + return (cacheProvider == _cacheProvider) ? this + : new DeserializationConfig(this, cacheProvider); + } } diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 8cecc2be70..ba86aa0442 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -206,7 +206,7 @@ protected DeserializationContext(DeserializationContext src, DeserializationConfig config, JsonParser p, InjectableValues injectableValues) { - _cache = src._cache; + _cache = src._cache.withCache(config.cacheProvider()); _factory = src._factory; // 08-Jun-2020. tatu: Called only for `ObjectMapper.canDeserialize()` // (see [databind#2749]), not sure what's the best work-around but @@ -230,7 +230,7 @@ protected DeserializationContext(DeserializationContext src, protected DeserializationContext(DeserializationContext src, DeserializationConfig config) { - _cache = src._cache; + _cache = src._cache.withCache(config.cacheProvider()); _factory = src._factory; _readCapabilities = null; diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index d903719aae..7b28199c05 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2267,6 +2267,19 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { return this; } + /** + * Method for specifying {@link ConstructorDetector} to use for + * determining some aspects of creator auto-detection (specifically + * auto-detection of constructor, and in particular behavior with + * single-argument constructors). + * + * @since 2.12 + */ + public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { + _deserializationConfig = _deserializationConfig.withCacheProvider(cacheProvider); + return this; + } + /** * Method for adding specified {@link DeserializationProblemHandler} * to be used for handling specific problems during deserialization. diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java index 836ed6e1bf..3ae4487a12 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java @@ -553,6 +553,11 @@ public B filterProvider(FilterProvider prov) { return _this(); } + public B cacheProvider(CacheProvider cacheProvider) { + _mapper.setCacheProvider(cacheProvider); + return _this(); + } + public B defaultPrettyPrinter(PrettyPrinter pp) { _mapper.setDefaultPrettyPrinter(pp); return _this(); @@ -922,8 +927,10 @@ public B setDefaultTyping(TypeResolverBuilder typer) { /* Other helper methods /********************************************************************** */ + // silly convenience cast method we need @SuppressWarnings("unchecked") protected final B _this() { return (B) this; } + } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 1dd7c8b081..1e5053141d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.util.ClassUtil; import com.fasterxml.jackson.databind.util.Converter; import com.fasterxml.jackson.databind.util.LRUMap; +import com.fasterxml.jackson.databind.util.LookupCache; /** * Class that defines caching layer between callers (like @@ -34,15 +35,14 @@ public final class DeserializerCache * specifically, ones that are expensive to construct. * This currently means bean, Enum and container deserializers. */ - final protected LRUMap> _cachedDeserializers; + final protected LookupCache> _cachedDeserializers; /** * During deserializer construction process we may need to keep track of partially * completed deserializers, to resolve cyclic dependencies. This is the * map used for storing deserializers before they are fully complete. */ - final protected HashMap> _incompleteDeserializers - = new HashMap>(8); + final protected HashMap> _incompleteDeserializers; /* /********************************************************** @@ -57,6 +57,21 @@ public DeserializerCache() { public DeserializerCache(int maxSize) { int initial = Math.min(64, maxSize>>2); _cachedDeserializers = new LRUMap<>(initial, maxSize); + _incompleteDeserializers = new HashMap>(8); + } + + public DeserializerCache(LookupCache> cachedDeserializers, + HashMap> incompleteDeserializers) { + _cachedDeserializers = cachedDeserializers; + _incompleteDeserializers = incompleteDeserializers; + } + + public DeserializerCache withCache(CacheProvider cacheProvider) { + LookupCache> cachedDeserializers = cacheProvider.provideForDeserializerCache(); + HashMap> incompleteDeserializers = + new HashMap>(8); + + return new DeserializerCache(cachedDeserializers, incompleteDeserializers); } /* diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java new file mode 100644 index 0000000000..210687ff28 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -0,0 +1,57 @@ +package com.fasterxml.jackson.databind.cfg; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.databind.util.LookupCache; +import org.junit.Test; + +import java.util.Map; + +public class CacheProviderTest extends BaseMapTest { + + static class RandomBean { + public int point; + } + + static class SimpleExampleCache implements LookupCache> { + int invocationCount = 0; + final Map> cache = new java.util.HashMap<>(); + + @Override + public int size() { + return cache.size(); + } + + @Override + public JsonDeserializer get(Object key) { + return cache.get(key); + } + + @Override + public JsonDeserializer put(JavaType key, JsonDeserializer value) { + return cache.put(key, value); + } + + @Override + public JsonDeserializer putIfAbsent(JavaType key, JsonDeserializer value) { + return cache.putIfAbsent(key, value); + } + + @Override + public void clear() { + cache.clear(); + } + } + + @Test + public void testCacheConfig() throws Exception { + CacheProvider cacheProvider = CacheProvider.builder() + .withTypeFactoryCache(new SimpleExampleCache()) + .build(); + + ObjectMapper mapper = JsonMapper.builder().cacheProvider(cacheProvider).build(); + + RandomBean bean = mapper.readValue("{\"point\":24}", RandomBean.class); + assertEquals(24, bean.point); + } +} From 3b0818a1318408fc7cc97b1afc8494cbbac96952 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 29 Aug 2023 08:17:00 +0900 Subject: [PATCH 02/53] Change name --- .../fasterxml/jackson/databind/CacheProvider.java | 12 ++++++------ .../jackson/databind/cfg/CacheProviderTest.java | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java index e1771dd47a..b2a14beb28 100644 --- a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java @@ -4,13 +4,13 @@ public class CacheProvider { - protected LookupCache> _typeFactoryCache; + protected LookupCache> _deserializerCache; protected CacheProvider() { } - protected CacheProvider forTypeFactory(LookupCache> cache) { - _typeFactoryCache = cache; + protected CacheProvider forDeserializerCache(LookupCache> cache) { + _deserializerCache = cache; return this; } @@ -25,7 +25,7 @@ public static CacheProvider.Builder builder() { } public LookupCache> provideForDeserializerCache() { - return _typeFactoryCache; + return _deserializerCache; } public static class Builder { @@ -47,8 +47,8 @@ public CacheProvider build() { /********************************************************** */ - public Builder withTypeFactoryCache(LookupCache> cache) { - cacheProvider._typeFactoryCache = cache; + public Builder forDeserializerCache(LookupCache> cache) { + cacheProvider._deserializerCache = cache; return this; } } diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 210687ff28..ed43a464f2 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -46,7 +46,7 @@ public void clear() { @Test public void testCacheConfig() throws Exception { CacheProvider cacheProvider = CacheProvider.builder() - .withTypeFactoryCache(new SimpleExampleCache()) + .forDeserializerCache(new SimpleExampleCache()) .build(); ObjectMapper mapper = JsonMapper.builder().cacheProvider(cacheProvider).build(); From 6bf55c2f133a7d8dee3d805ee855836641cf09a6 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 29 Aug 2023 23:26:25 +0900 Subject: [PATCH 03/53] Apply review --- .../databind/deser/DeserializerCache.java | 24 +++++++------- .../databind/cfg/CacheProviderTest.java | 32 ++++++++++++------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 1e5053141d..42da5beded 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -34,6 +34,8 @@ public final class DeserializerCache * We will also cache some dynamically constructed deserializers; * specifically, ones that are expensive to construct. * This currently means bean, Enum and container deserializers. + *

+ * Since 2.16, changed its type from {@link LRUMap} to {@link LookupCache} */ final protected LookupCache> _cachedDeserializers; @@ -42,7 +44,8 @@ public final class DeserializerCache * completed deserializers, to resolve cyclic dependencies. This is the * map used for storing deserializers before they are fully complete. */ - final protected HashMap> _incompleteDeserializers; + final protected HashMap> _incompleteDeserializers + = new HashMap>(8); /* /********************************************************** @@ -57,21 +60,20 @@ public DeserializerCache() { public DeserializerCache(int maxSize) { int initial = Math.min(64, maxSize>>2); _cachedDeserializers = new LRUMap<>(initial, maxSize); - _incompleteDeserializers = new HashMap>(8); } - public DeserializerCache(LookupCache> cachedDeserializers, - HashMap> incompleteDeserializers) { + /** + * @since 2.16 + */ + protected DeserializerCache(LookupCache> cachedDeserializers) { _cachedDeserializers = cachedDeserializers; - _incompleteDeserializers = incompleteDeserializers; } - + + /** + * @since 2.16 + */ public DeserializerCache withCache(CacheProvider cacheProvider) { - LookupCache> cachedDeserializers = cacheProvider.provideForDeserializerCache(); - HashMap> incompleteDeserializers = - new HashMap>(8); - - return new DeserializerCache(cachedDeserializers, incompleteDeserializers); + return new DeserializerCache(cacheProvider.provideForDeserializerCache()); } /* diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index ed43a464f2..26c11ee69e 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -5,20 +5,29 @@ import com.fasterxml.jackson.databind.util.LookupCache; import org.junit.Test; -import java.util.Map; +import java.util.HashMap; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * + * [databind#2502] Test for adding a way to configure Caches Jackson uses + * + * @since 2.16 + */ +public class CacheProviderTest +{ -public class CacheProviderTest extends BaseMapTest { - static class RandomBean { public int point; } - static class SimpleExampleCache implements LookupCache> { - int invocationCount = 0; - final Map> cache = new java.util.HashMap<>(); + static class SimpleTestCache implements LookupCache> { + + final HashMap> cache = new HashMap<>(); @Override - public int size() { + public int size(){ return cache.size(); } @@ -44,13 +53,14 @@ public void clear() { } @Test - public void testCacheConfig() throws Exception { + public void testCacheConfig() throws Exception + { CacheProvider cacheProvider = CacheProvider.builder() - .forDeserializerCache(new SimpleExampleCache()) + .forDeserializerCache(new SimpleTestCache()) .build(); - + ObjectMapper mapper = JsonMapper.builder().cacheProvider(cacheProvider).build(); - + RandomBean bean = mapper.readValue("{\"point\":24}", RandomBean.class); assertEquals(24, bean.point); } From d49dbb37b969e182e22128a2ae7e253f3b09130a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 29 Aug 2023 23:55:12 +0900 Subject: [PATCH 04/53] Clean up changes --- .../jackson/databind/CacheProvider.java | 19 +++++++++----- .../databind/DeserializationConfig.java | 26 ++++++++++++++----- .../databind/DeserializationContext.java | 7 +++-- .../jackson/databind/ObjectMapper.java | 7 ++--- .../jackson/databind/cfg/MapperBuilder.java | 15 ++++++----- .../databind/cfg/MapperConfigBase.java | 2 +- .../databind/deser/DeserializerCache.java | 3 +++ 7 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java index b2a14beb28..f4bf4ae69b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java @@ -2,14 +2,22 @@ import com.fasterxml.jackson.databind.util.LookupCache; -public class CacheProvider { +/** + * Container for {@link LookupCache} instances to use to override default cache implementations used. + * Should only be configured via {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)}. + * + * @since 2.16 + */ +public class CacheProvider + implements java.io.Serializable +{ + private static final long serialVersionUID = 1L; // 2.6 protected LookupCache> _deserializerCache; - protected CacheProvider() { - } + protected CacheProvider() { } - protected CacheProvider forDeserializerCache(LookupCache> cache) { + protected CacheProvider setDeserializerCache(LookupCache> cache) { _deserializerCache = cache; return this; } @@ -40,7 +48,6 @@ public CacheProvider build() { return cacheProvider; } - /* /********************************************************** /* Configuration using Builder @@ -48,7 +55,7 @@ public CacheProvider build() { */ public Builder forDeserializerCache(LookupCache> cache) { - cacheProvider._deserializerCache = cache; + cacheProvider.setDeserializerCache(cache); return this; } } diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index db373a61d1..eea9ba58e3 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -6,13 +6,11 @@ import com.fasterxml.jackson.core.json.JsonReadFeature; import com.fasterxml.jackson.databind.cfg.*; import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler; -import com.fasterxml.jackson.databind.deser.DeserializerCache; import com.fasterxml.jackson.databind.introspect.*; import com.fasterxml.jackson.databind.jsontype.*; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.type.LogicalType; import com.fasterxml.jackson.databind.util.LinkedNode; -import com.fasterxml.jackson.databind.util.LookupCache; import com.fasterxml.jackson.databind.util.RootNameLookup; /** @@ -102,7 +100,12 @@ public final class DeserializationConfig * @since 2.7 */ protected final int _formatReadFeaturesToChange; - + + /** + * Used to provide custom cache implementation in downstream components. + * + * @since 2.16 + */ protected CacheProvider _cacheProvider; /* @@ -329,6 +332,9 @@ protected DeserializationConfig(DeserializationConfig src, _formatReadFeaturesToChange = src._formatReadFeaturesToChange; } + /** + * @since 2.16 + */ public DeserializationConfig(DeserializationConfig src, CacheProvider cacheProvider) { super(src); _deserFeatures = src._deserFeatures; @@ -939,8 +945,11 @@ public ConstructorDetector getConstructorDetector() { } return _ctorDetector; } - - public CacheProvider cacheProvider() { + + /** + * @since 2.16 + */ + public CacheProvider getCacheProvider() { return _cacheProvider; } @@ -1069,8 +1078,11 @@ public CoercionAction findCoercionFromBlankString(LogicalType targetType, targetType, targetClass, actionIfBlankNotAllowed); } + /** + * @return New instance of {@link DeserializationConfig} with configured {@link CacheProvider}. + * @since 2.16 + */ public DeserializationConfig withCacheProvider(CacheProvider cacheProvider) { - return (cacheProvider == _cacheProvider) ? this - : new DeserializationConfig(this, cacheProvider); + return (cacheProvider == _cacheProvider) ? this : new DeserializationConfig(this, cacheProvider); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index ba86aa0442..c07332c9da 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -206,7 +206,10 @@ protected DeserializationContext(DeserializationContext src, DeserializationConfig config, JsonParser p, InjectableValues injectableValues) { - _cache = src._cache.withCache(config.cacheProvider()); +// _cache = src._cache; +// _cache = config.getCacheProvider() == null ? _cache : _cache.withCache(config.getCacheProvider()); + _cache = src._cache.withCache(config.getCacheProvider()); + _factory = src._factory; // 08-Jun-2020. tatu: Called only for `ObjectMapper.canDeserialize()` // (see [databind#2749]), not sure what's the best work-around but @@ -230,7 +233,7 @@ protected DeserializationContext(DeserializationContext src, protected DeserializationContext(DeserializationContext src, DeserializationConfig config) { - _cache = src._cache.withCache(config.cacheProvider()); + _cache = src._cache.withCache(config.getCacheProvider()); _factory = src._factory; _readCapabilities = null; diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 7b28199c05..b7d1dd3f46 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2268,12 +2268,9 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { } /** - * Method for specifying {@link ConstructorDetector} to use for - * determining some aspects of creator auto-detection (specifically - * auto-detection of constructor, and in particular behavior with - * single-argument constructors). + * Method for specifying {@link CacheProvider} to provide Cache instances to be used in components downstream. * - * @since 2.12 + * @since 2.16 */ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { _deserializationConfig = _deserializationConfig.withCacheProvider(cacheProvider); diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java index 3ae4487a12..daaf79780b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java @@ -553,11 +553,6 @@ public B filterProvider(FilterProvider prov) { return _this(); } - public B cacheProvider(CacheProvider cacheProvider) { - _mapper.setCacheProvider(cacheProvider); - return _this(); - } - public B defaultPrettyPrinter(PrettyPrinter pp) { _mapper.setDefaultPrettyPrinter(pp); return _this(); @@ -611,6 +606,14 @@ public B clearProblemHandlers() { return _this(); } + /** + * @since 2.16 + */ + public B cacheProvider(CacheProvider cacheProvider) { + _mapper.setCacheProvider(cacheProvider); + return _this(); + } + /* /********************************************************************** /* Changing global defaults @@ -927,10 +930,8 @@ public B setDefaultTyping(TypeResolverBuilder typer) { /* Other helper methods /********************************************************************** */ - // silly convenience cast method we need @SuppressWarnings("unchecked") protected final B _this() { return (B) this; } - } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java index b954080469..dc2c9351da 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java @@ -896,7 +896,7 @@ public PropertyName findRootName(Class rawRootType) { } return _rootNames.findRootName(rawRootType, this); } - + /* /********************************************************************** /* ClassIntrospector.MixInResolver impl: diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 42da5beded..eca47d9c38 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -73,6 +73,9 @@ protected DeserializerCache(LookupCache> cach * @since 2.16 */ public DeserializerCache withCache(CacheProvider cacheProvider) { + if (cacheProvider == null) { + return this; + } return new DeserializerCache(cacheProvider.provideForDeserializerCache()); } From c71779fb5071feba3ea56919a60399337d730876 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 00:01:15 +0900 Subject: [PATCH 05/53] Fix DeserializationConfig constructor accessor --- .../com/fasterxml/jackson/databind/DeserializationConfig.java | 2 +- .../com/fasterxml/jackson/databind/cfg/MapperConfigBase.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index eea9ba58e3..f64621863d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -335,7 +335,7 @@ protected DeserializationConfig(DeserializationConfig src, /** * @since 2.16 */ - public DeserializationConfig(DeserializationConfig src, CacheProvider cacheProvider) { + protected DeserializationConfig(DeserializationConfig src, CacheProvider cacheProvider) { super(src); _deserFeatures = src._deserFeatures; _problemHandlers = src._problemHandlers; diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java index dc2c9351da..b954080469 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java @@ -896,7 +896,7 @@ public PropertyName findRootName(Class rawRootType) { } return _rootNames.findRootName(rawRootType, this); } - + /* /********************************************************************** /* ClassIntrospector.MixInResolver impl: From ea77d79b05c2bd81bc69e6f65caa7fb76f873367 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 00:01:54 +0900 Subject: [PATCH 06/53] Clean up commented out code --- .../com/fasterxml/jackson/databind/DeserializationContext.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index c07332c9da..0e7285efc0 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -206,10 +206,7 @@ protected DeserializationContext(DeserializationContext src, DeserializationConfig config, JsonParser p, InjectableValues injectableValues) { -// _cache = src._cache; -// _cache = config.getCacheProvider() == null ? _cache : _cache.withCache(config.getCacheProvider()); _cache = src._cache.withCache(config.getCacheProvider()); - _factory = src._factory; // 08-Jun-2020. tatu: Called only for `ObjectMapper.canDeserialize()` // (see [databind#2749]), not sure what's the best work-around but From f2b43c4500e7638b5b7c71b1681a68b2c75dca19 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 08:48:01 +0900 Subject: [PATCH 07/53] Create interface for CacheProvider --- .../jackson/databind/CacheProvider.java | 56 ++--------------- .../databind/DefaultCacheProvider.java | 63 +++++++++++++++++++ .../databind/DeserializationConfig.java | 10 +-- .../jackson/databind/ObjectMapper.java | 4 +- .../jackson/databind/cfg/MapperBuilder.java | 2 +- .../databind/deser/DeserializerCache.java | 4 +- .../databind/cfg/CacheProviderTest.java | 2 +- 7 files changed, 78 insertions(+), 63 deletions(-) create mode 100644 src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java diff --git a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java index f4bf4ae69b..163f705d20 100644 --- a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java @@ -3,60 +3,12 @@ import com.fasterxml.jackson.databind.util.LookupCache; /** - * Container for {@link LookupCache} instances to use to override default cache implementations used. - * Should only be configured via {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)}. + * Interface that defines API for Cache configurations. * * @since 2.16 */ -public class CacheProvider - implements java.io.Serializable -{ - private static final long serialVersionUID = 1L; // 2.6 - - protected LookupCache> _deserializerCache; - - protected CacheProvider() { } +public interface CacheProvider { + + LookupCache> provideDeserializerCache(); - protected CacheProvider setDeserializerCache(LookupCache> cache) { - _deserializerCache = cache; - return this; - } - - /* - /********************************************************** - /* Builder Initialization - /********************************************************** - */ - - public static CacheProvider.Builder builder() { - return new Builder(new CacheProvider()); - } - - public LookupCache> provideForDeserializerCache() { - return _deserializerCache; - } - - public static class Builder { - - protected final CacheProvider cacheProvider; - - public Builder(CacheProvider cacheProvider) { - this.cacheProvider = cacheProvider; - } - - public CacheProvider build() { - return cacheProvider; - } - - /* - /********************************************************** - /* Configuration using Builder - /********************************************************** - */ - - public Builder forDeserializerCache(LookupCache> cache) { - cacheProvider.setDeserializerCache(cache); - return this; - } - } } diff --git a/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java new file mode 100644 index 0000000000..52daae980a --- /dev/null +++ b/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java @@ -0,0 +1,63 @@ +package com.fasterxml.jackson.databind; + +import com.fasterxml.jackson.databind.util.LookupCache; + +/** + * Container for {@link LookupCache} instances to use to override default cache implementations used. + * Should only be configured via {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(DefaultCacheProvider)}. + * + * @since 2.16 + */ +public class DefaultCacheProvider + implements CacheProvider, java.io.Serializable +{ + private static final long serialVersionUID = 1L; // 2.6 + + protected LookupCache> _deserializerCache; + + protected DefaultCacheProvider() { } + + protected DefaultCacheProvider setDeserializerCache(LookupCache> cache) { + _deserializerCache = cache; + return this; + } + + /* + /********************************************************** + /* Cache accessors + /********************************************************** + */ + + @Override + public LookupCache> provideDeserializerCache() { + return _deserializerCache; + } + + /* + /********************************************************** + /* Configuration using Builder + /********************************************************** + */ + + public static DefaultCacheProvider.Builder builder() { + return new Builder(new DefaultCacheProvider()); + } + + public static class Builder { + + protected final DefaultCacheProvider cacheProvider; + + public Builder(DefaultCacheProvider cacheProvider) { + this.cacheProvider = cacheProvider; + } + + public DefaultCacheProvider build() { + return cacheProvider; + } + + public Builder forDeserializerCache(LookupCache> cache) { + cacheProvider.setDeserializerCache(cache); + return this; + } + } +} diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index f64621863d..48e28393a2 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -106,7 +106,7 @@ public final class DeserializationConfig * * @since 2.16 */ - protected CacheProvider _cacheProvider; + protected DefaultCacheProvider _cacheProvider; /* /********************************************************** @@ -335,7 +335,7 @@ protected DeserializationConfig(DeserializationConfig src, /** * @since 2.16 */ - protected DeserializationConfig(DeserializationConfig src, CacheProvider cacheProvider) { + protected DeserializationConfig(DeserializationConfig src, DefaultCacheProvider cacheProvider) { super(src); _deserFeatures = src._deserFeatures; _problemHandlers = src._problemHandlers; @@ -949,7 +949,7 @@ public ConstructorDetector getConstructorDetector() { /** * @since 2.16 */ - public CacheProvider getCacheProvider() { + public DefaultCacheProvider getCacheProvider() { return _cacheProvider; } @@ -1079,10 +1079,10 @@ public CoercionAction findCoercionFromBlankString(LogicalType targetType, } /** - * @return New instance of {@link DeserializationConfig} with configured {@link CacheProvider}. + * @return New instance of {@link DeserializationConfig} with configured {@link DefaultCacheProvider}. * @since 2.16 */ - public DeserializationConfig withCacheProvider(CacheProvider cacheProvider) { + public DeserializationConfig withCacheProvider(DefaultCacheProvider cacheProvider) { return (cacheProvider == _cacheProvider) ? this : new DeserializationConfig(this, cacheProvider); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index b7d1dd3f46..3878cd7a2d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2268,11 +2268,11 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { } /** - * Method for specifying {@link CacheProvider} to provide Cache instances to be used in components downstream. + * Method for specifying {@link DefaultCacheProvider} to provide Cache instances to be used in components downstream. * * @since 2.16 */ - public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { + public ObjectMapper setCacheProvider(DefaultCacheProvider cacheProvider) { _deserializationConfig = _deserializationConfig.withCacheProvider(cacheProvider); return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java index daaf79780b..f7685e7700 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java @@ -609,7 +609,7 @@ public B clearProblemHandlers() { /** * @since 2.16 */ - public B cacheProvider(CacheProvider cacheProvider) { + public B cacheProvider(DefaultCacheProvider cacheProvider) { _mapper.setCacheProvider(cacheProvider); return _this(); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index eca47d9c38..eb1cffb80e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -72,11 +72,11 @@ protected DeserializerCache(LookupCache> cach /** * @since 2.16 */ - public DeserializerCache withCache(CacheProvider cacheProvider) { + public DeserializerCache withCache(DefaultCacheProvider cacheProvider) { if (cacheProvider == null) { return this; } - return new DeserializerCache(cacheProvider.provideForDeserializerCache()); + return new DeserializerCache(cacheProvider.provideDeserializerCache()); } /* diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 26c11ee69e..1e30408cdd 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -55,7 +55,7 @@ public void clear() { @Test public void testCacheConfig() throws Exception { - CacheProvider cacheProvider = CacheProvider.builder() + DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() .forDeserializerCache(new SimpleTestCache()) .build(); From 3028b0cc77cf11be5836d17e0ce15478df8fcc2d Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 12:45:15 +0900 Subject: [PATCH 08/53] Change DefaultCacheProvider to CacheProvider as param type --- .../databind/DeserializationConfig.java | 29 ++++++++++++++----- .../jackson/databind/ObjectMapper.java | 4 +-- .../jackson/databind/cfg/MapperBuilder.java | 2 +- .../databind/deser/DeserializerCache.java | 2 +- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index 48e28393a2..9beea1043d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -1,6 +1,8 @@ package com.fasterxml.jackson.databind; +import java.io.Serializable; import java.util.*; +import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.json.JsonReadFeature; @@ -106,7 +108,7 @@ public final class DeserializationConfig * * @since 2.16 */ - protected DefaultCacheProvider _cacheProvider; + protected final CacheProvider _cacheProvider; /* /********************************************************** @@ -134,6 +136,7 @@ public DeserializationConfig(BaseSettings base, _parserFeaturesToChange = 0; _formatReadFeatures = 0; _formatReadFeaturesToChange = 0; + _cacheProvider = null; } /** @@ -156,6 +159,7 @@ protected DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } /* @@ -180,6 +184,7 @@ private DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = parserFeatureMask; _formatReadFeatures = formatFeatures; _formatReadFeaturesToChange = formatFeatureMask; + _cacheProvider = src._cacheProvider; } /** @@ -198,6 +203,7 @@ private DeserializationConfig(DeserializationConfig src, SubtypeResolver str) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, BaseSettings base) @@ -212,6 +218,7 @@ private DeserializationConfig(DeserializationConfig src, BaseSettings base) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, JsonNodeFactory f) @@ -226,6 +233,7 @@ private DeserializationConfig(DeserializationConfig src, JsonNodeFactory f) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } // @since 2.12 @@ -241,6 +249,7 @@ private DeserializationConfig(DeserializationConfig src, ConstructorDetector cto _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, @@ -256,6 +265,7 @@ private DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, PropertyName rootName) @@ -270,6 +280,7 @@ private DeserializationConfig(DeserializationConfig src, PropertyName rootName) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, Class view) @@ -284,6 +295,7 @@ private DeserializationConfig(DeserializationConfig src, Class view) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } protected DeserializationConfig(DeserializationConfig src, ContextAttributes attrs) @@ -298,6 +310,7 @@ protected DeserializationConfig(DeserializationConfig src, ContextAttributes att _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } protected DeserializationConfig(DeserializationConfig src, SimpleMixInResolver mixins) @@ -312,6 +325,7 @@ protected DeserializationConfig(DeserializationConfig src, SimpleMixInResolver m _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = src._cacheProvider; } /** @@ -330,12 +344,13 @@ protected DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; + _cacheProvider = null; } /** * @since 2.16 */ - protected DeserializationConfig(DeserializationConfig src, DefaultCacheProvider cacheProvider) { + protected DeserializationConfig(DeserializationConfig src, CacheProvider cacheProvider) { super(src); _deserFeatures = src._deserFeatures; _problemHandlers = src._problemHandlers; @@ -797,7 +812,7 @@ public DeserializationConfig withNoProblemHandlers() { /** * Method called by {@link ObjectMapper} and {@link ObjectReader} - * to modify those {@link com.fasterxml.jackson.core.JsonParser.Feature} settings + * to modify those {@link JsonParser.Feature} settings * that have been configured via this config instance. * * @since 2.5 @@ -949,7 +964,7 @@ public ConstructorDetector getConstructorDetector() { /** * @since 2.16 */ - public DefaultCacheProvider getCacheProvider() { + public CacheProvider getCacheProvider() { return _cacheProvider; } @@ -1002,7 +1017,7 @@ public BeanDescription introspectForBuilder(JavaType type) { /** * Helper method that is needed to properly handle polymorphic referenced - * types, such as types referenced by {@link java.util.concurrent.atomic.AtomicReference}, + * types, such as types referenced by {@link AtomicReference}, * or various "optional" types. * * @since 2.4 @@ -1079,10 +1094,10 @@ public CoercionAction findCoercionFromBlankString(LogicalType targetType, } /** - * @return New instance of {@link DeserializationConfig} with configured {@link DefaultCacheProvider}. + * @return New instance of {@link DeserializationConfig} with configured {@link CacheProvider}. * @since 2.16 */ - public DeserializationConfig withCacheProvider(DefaultCacheProvider cacheProvider) { + public DeserializationConfig withCacheProvider(CacheProvider cacheProvider) { return (cacheProvider == _cacheProvider) ? this : new DeserializationConfig(this, cacheProvider); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 3878cd7a2d..807b995caf 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2268,11 +2268,11 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { } /** - * Method for specifying {@link DefaultCacheProvider} to provide Cache instances to be used in components downstream. + * Method for specifying {@link CacheProvider} instance, to provide Cache instances to be used in components downstream. * * @since 2.16 */ - public ObjectMapper setCacheProvider(DefaultCacheProvider cacheProvider) { + public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { _deserializationConfig = _deserializationConfig.withCacheProvider(cacheProvider); return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java index f7685e7700..daaf79780b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java @@ -609,7 +609,7 @@ public B clearProblemHandlers() { /** * @since 2.16 */ - public B cacheProvider(DefaultCacheProvider cacheProvider) { + public B cacheProvider(CacheProvider cacheProvider) { _mapper.setCacheProvider(cacheProvider); return _this(); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index eb1cffb80e..033909cc32 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -72,7 +72,7 @@ protected DeserializerCache(LookupCache> cach /** * @since 2.16 */ - public DeserializerCache withCache(DefaultCacheProvider cacheProvider) { + public DeserializerCache withCache(CacheProvider cacheProvider) { if (cacheProvider == null) { return this; } From 3b53c7684373cf36c5232dbc9bd457ef45a9948a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 12:58:40 +0900 Subject: [PATCH 09/53] Remove cache mutation in deserialization config --- .../com/fasterxml/jackson/databind/DeserializationContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 0e7285efc0..49c88bf9f8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -206,7 +206,7 @@ protected DeserializationContext(DeserializationContext src, DeserializationConfig config, JsonParser p, InjectableValues injectableValues) { - _cache = src._cache.withCache(config.getCacheProvider()); + _cache = src._cache; _factory = src._factory; // 08-Jun-2020. tatu: Called only for `ObjectMapper.canDeserialize()` // (see [databind#2749]), not sure what's the best work-around but From 64ae8314e01e63135853e4cc931f459999a54716 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 20:06:47 +0900 Subject: [PATCH 10/53] Update CacheProviderTest.java --- .../jackson/databind/cfg/CacheProviderTest.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 1e30408cdd..a873ae33f5 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -7,7 +7,7 @@ import java.util.HashMap; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; /** * @@ -25,6 +25,8 @@ static class RandomBean { static class SimpleTestCache implements LookupCache> { final HashMap> cache = new HashMap<>(); + // Checking the cache was actually used + boolean invoked = false; @Override public int size(){ @@ -33,16 +35,19 @@ public int size(){ @Override public JsonDeserializer get(Object key) { + invoked = true; return cache.get(key); } @Override public JsonDeserializer put(JavaType key, JsonDeserializer value) { + invoked = true; return cache.put(key, value); } @Override public JsonDeserializer putIfAbsent(JavaType key, JsonDeserializer value) { + invoked = true; return cache.putIfAbsent(key, value); } @@ -55,13 +60,14 @@ public void clear() { @Test public void testCacheConfig() throws Exception { + LookupCache> cache = new SimpleTestCache(); DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .forDeserializerCache(new SimpleTestCache()) + .forDeserializerCache(cache) .build(); - ObjectMapper mapper = JsonMapper.builder().cacheProvider(cacheProvider).build(); RandomBean bean = mapper.readValue("{\"point\":24}", RandomBean.class); assertEquals(24, bean.point); + assertTrue(((SimpleTestCache) cache).invoked); } } From 30adc848d29b747e852ee73f8372cac984e11398 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 22:51:08 +0900 Subject: [PATCH 11/53] Apply review --- .../jackson/databind/CacheProvider.java | 14 ++++- .../jackson/databind/DatabindContext.java | 10 ++++ .../databind/DefaultCacheProvider.java | 54 +++++++++++-------- .../databind/DeserializationContext.java | 19 ++++++- .../jackson/databind/ObjectMapper.java | 2 + .../deser/DefaultDeserializationContext.java | 18 +++++++ .../databind/deser/DeserializerCache.java | 14 +---- .../ser/DefaultSerializerProvider.java | 6 +++ .../databind/cfg/CacheProviderTest.java | 32 ++++++----- 9 files changed, 118 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java index 163f705d20..123cb7e2af 100644 --- a/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/CacheProvider.java @@ -1,14 +1,24 @@ package com.fasterxml.jackson.databind; +import com.fasterxml.jackson.databind.deser.DeserializerCache; import com.fasterxml.jackson.databind.util.LookupCache; /** - * Interface that defines API for Cache configurations. + * Interface that defines API for custom Cache configuration that overrides default cache implementations used. + * A {@link CacheProvider} instance will be configured through a builder such as + * {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)} * * @since 2.16 */ -public interface CacheProvider { +public interface CacheProvider + extends java.io.Serializable +{ + /** + * Method to provide a {@link LookupCache} instance for {@link DeserializerCache} + * + * @return {@link LookupCache} instance for caching {@link JsonDeserializer}s + */ LookupCache> provideDeserializerCache(); } diff --git a/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java b/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java index be2fd7d428..bf831fd1b9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java @@ -148,6 +148,16 @@ public abstract class DatabindContext */ public abstract DatabindContext setAttribute(Object key, Object value); + /** + * Method to configure a provider for custom cache implementations downstream. + * Should be overriden by sub-classes. + * + * @since 2.16 + */ + public DatabindContext withCacheProvider(CacheProvider cacheProvider) { + return this; + } + /* /********************************************************** /* Type instantiation/resolution diff --git a/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java index 52daae980a..4a355726c0 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java @@ -1,27 +1,34 @@ package com.fasterxml.jackson.databind; +import com.fasterxml.jackson.databind.deser.DeserializerCache; import com.fasterxml.jackson.databind.util.LookupCache; +import java.util.function.Supplier; + /** - * Container for {@link LookupCache} instances to use to override default cache implementations used. - * Should only be configured via {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(DefaultCacheProvider)}. + * Default implementation of {@link CacheProvider} that provides easy, builder-based custom cache configuration + * using {@link DefaultCacheProvider.Builder}. + *

+ * Users can either use this class or implement their own {@link CacheProvider} imlementation. * * @since 2.16 */ public class DefaultCacheProvider - implements CacheProvider, java.io.Serializable + implements CacheProvider { - private static final long serialVersionUID = 1L; // 2.6 - protected LookupCache> _deserializerCache; + private static final long serialVersionUID = 1L; - protected DefaultCacheProvider() { } - - protected DefaultCacheProvider setDeserializerCache(LookupCache> cache) { - _deserializerCache = cache; - return this; - } + /** + * Supplier of cache instance to be used by {@link DeserializerCache}. + */ + protected final Supplier>> _deserializerCacheSupplier; + protected DefaultCacheProvider(Supplier>> deserializerCache) + { + _deserializerCacheSupplier = deserializerCache; + } + /* /********************************************************** /* Cache accessors @@ -30,7 +37,7 @@ protected DefaultCacheProvider setDeserializerCache(LookupCache> provideDeserializerCache() { - return _deserializerCache; + return _deserializerCacheSupplier.get(); } /* @@ -40,23 +47,28 @@ public LookupCache> provideDeserializerCache( */ public static DefaultCacheProvider.Builder builder() { - return new Builder(new DefaultCacheProvider()); + return new Builder(); } + /** + * Builder class to construct {@link DefaultCacheProvider} instance + * and to keep {@link DefaultCacheProvider} immutable. + */ public static class Builder { - - protected final DefaultCacheProvider cacheProvider; - public Builder(DefaultCacheProvider cacheProvider) { - this.cacheProvider = cacheProvider; - } + /** + * Supplier of cache instance to be used by {@link DeserializerCache}. + */ + private Supplier>> _deserializerCacheSupplier; + + protected Builder() { } public DefaultCacheProvider build() { - return cacheProvider; + return new DefaultCacheProvider(_deserializerCacheSupplier); } - public Builder forDeserializerCache(LookupCache> cache) { - cacheProvider.setDeserializerCache(cache); + public Builder deserializerCache(Supplier>> deserializerCache) { + _deserializerCacheSupplier = deserializerCache; return this; } } diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 49c88bf9f8..65581ed626 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -230,7 +230,7 @@ protected DeserializationContext(DeserializationContext src, protected DeserializationContext(DeserializationContext src, DeserializationConfig config) { - _cache = src._cache.withCache(config.getCacheProvider()); + _cache = src._cache; _factory = src._factory; _readCapabilities = null; @@ -246,7 +246,6 @@ protected DeserializationContext(DeserializationContext src, * Copy-constructor for use with copy() by {@link ObjectMapper#copy()} */ protected DeserializationContext(DeserializationContext src) { - _cache = new DeserializerCache(); _factory = src._factory; _config = src._config; @@ -254,6 +253,22 @@ protected DeserializationContext(DeserializationContext src) { _readCapabilities = src._readCapabilities; _view = src._view; _injectableValues = null; + _cache = (src._config == null) ? new DeserializerCache() + : new DeserializerCache(src._config.getCacheProvider()); + } + + /** + * @since 2.16 + */ + public DeserializationContext(DefaultDeserializationContext src, DeserializerCache deserializerCache) { + _factory = src._factory; + + _config = src._config; + _featureFlags = src._featureFlags; + _readCapabilities = src._readCapabilities; + _view = src._view; + _injectableValues = src._injectableValues; + _cache = deserializerCache; } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 807b995caf..c672c51763 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2274,6 +2274,8 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { */ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { _deserializationConfig = _deserializationConfig.withCacheProvider(cacheProvider); + _deserializationContext = _deserializationContext.withCacheProvider(cacheProvider); + // TODO: implement also serialization side return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 0e57e3ccb0..0bd88cb450 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -68,6 +68,10 @@ protected DefaultDeserializationContext(DefaultDeserializationContext src) { super(src); } + public DefaultDeserializationContext(DefaultDeserializationContext src, DeserializerCache deserializerCache) { + super(src, deserializerCache); + } + /** * Method needed to ensure that {@link ObjectMapper#copy} will work * properly; specifically, that caches are cleared, but settings @@ -80,6 +84,11 @@ public DefaultDeserializationContext copy() { throw new IllegalStateException("DefaultDeserializationContext sub-class not overriding copy()"); } + @Override + public DefaultDeserializationContext withCacheProvider(CacheProvider cacheProvider) { + throw new IllegalStateException("DefaultDeserializationContext sub-class not overriding withCacheProvider(CacheProvider)"); + } + /* /********************************************************** /* Abstract methods impls, Object Id @@ -402,6 +411,10 @@ private Impl(Impl src, DeserializationConfig config) { super(src, config); } + private Impl(Impl src, DeserializerCache cache) { + super(src, cache); + } + @Override public DefaultDeserializationContext copy() { ClassUtil.verifyMustOverride(Impl.class, this, "copy"); @@ -424,5 +437,10 @@ public DefaultDeserializationContext createDummyInstance(DeserializationConfig c public DefaultDeserializationContext with(DeserializerFactory factory) { return new Impl(this, factory); } + + @Override + public DefaultDeserializationContext withCacheProvider(CacheProvider cacheProvider) { + return new Impl(this, new DeserializerCache(cacheProvider)); + } } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 033909cc32..b232af3ef3 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -65,18 +65,8 @@ public DeserializerCache(int maxSize) { /** * @since 2.16 */ - protected DeserializerCache(LookupCache> cachedDeserializers) { - _cachedDeserializers = cachedDeserializers; - } - - /** - * @since 2.16 - */ - public DeserializerCache withCache(CacheProvider cacheProvider) { - if (cacheProvider == null) { - return this; - } - return new DeserializerCache(cacheProvider.provideDeserializerCache()); + public DeserializerCache(CacheProvider cacheProvider) { + _cachedDeserializers = cacheProvider.provideDeserializerCache(); } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java b/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java index 2c9f0ac6f9..fcb7c5b508 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java @@ -627,5 +627,11 @@ public DefaultSerializerProvider copy() public Impl createInstance(SerializationConfig config, SerializerFactory jsf) { return new Impl(this, config, jsf); } + + @Override + public Impl withCacheProvider(CacheProvider cacheProvider) { + // TODO: implement like {@code DefaultDeserializationContext.Impl#withCacheProvider} + return this; + } } } diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index a873ae33f5..527dcd1c8f 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -1,22 +1,26 @@ package com.fasterxml.jackson.databind.cfg; -import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.DefaultCacheProvider; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.util.LookupCache; import org.junit.Test; import java.util.HashMap; +import java.util.function.Supplier; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * * [databind#2502] Test for adding a way to configure Caches Jackson uses - * + * * @since 2.16 */ -public class CacheProviderTest -{ +public class CacheProviderTest { static class RandomBean { public int point; @@ -25,11 +29,9 @@ static class RandomBean { static class SimpleTestCache implements LookupCache> { final HashMap> cache = new HashMap<>(); - // Checking the cache was actually used - boolean invoked = false; @Override - public int size(){ + public int size() { return cache.size(); } @@ -57,17 +59,19 @@ public void clear() { } } + // Checking the cache was actually used + private static boolean invoked = false; + @Test - public void testCacheConfig() throws Exception - { - LookupCache> cache = new SimpleTestCache(); + public void testCacheConfig() throws Exception { DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .forDeserializerCache(cache) + .deserializerCache(() -> new SimpleTestCache()) .build(); - ObjectMapper mapper = JsonMapper.builder().cacheProvider(cacheProvider).build(); + ObjectMapper mapper = JsonMapper.builder() + .cacheProvider(cacheProvider).build(); RandomBean bean = mapper.readValue("{\"point\":24}", RandomBean.class); assertEquals(24, bean.point); - assertTrue(((SimpleTestCache) cache).invoked); + assertTrue(invoked); } } From a36b1d507db51020a055b2f4fcfce2022f74001c Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 22:58:41 +0900 Subject: [PATCH 12/53] not specify _cacheProvider as null --- .../com/fasterxml/jackson/databind/DeserializationConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index 9beea1043d..241daf8a34 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -344,7 +344,7 @@ protected DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = null; + _cacheProvider = src._cacheProvider; } /** From 272ef1d322194346a8c0214ea872cb72dc5c7f3f Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 23:16:16 +0900 Subject: [PATCH 13/53] Minimize changes --- .../fasterxml/jackson/databind/DeserializationConfig.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index 241daf8a34..a0d6cdc765 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -1,8 +1,6 @@ package com.fasterxml.jackson.databind; -import java.io.Serializable; import java.util.*; -import java.util.concurrent.atomic.AtomicReference; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.json.JsonReadFeature; @@ -812,7 +810,7 @@ public DeserializationConfig withNoProblemHandlers() { /** * Method called by {@link ObjectMapper} and {@link ObjectReader} - * to modify those {@link JsonParser.Feature} settings + * to modify those {@link com.fasterxml.jackson.core.JsonParser.Feature} settings * that have been configured via this config instance. * * @since 2.5 @@ -1017,7 +1015,7 @@ public BeanDescription introspectForBuilder(JavaType type) { /** * Helper method that is needed to properly handle polymorphic referenced - * types, such as types referenced by {@link AtomicReference}, + * types, such as types referenced by {@link java.util.concurrent.atomic.AtomicReference}, * or various "optional" types. * * @since 2.4 From a37f7403575fb5fd0134229232e118588574062c Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Wed, 30 Aug 2023 23:30:20 +0900 Subject: [PATCH 14/53] Remove supplier --- .../jackson/databind/DefaultCacheProvider.java | 16 ++++++++-------- .../jackson/databind/DeserializationContext.java | 3 +-- .../jackson/databind/cfg/CacheProviderTest.java | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java index 4a355726c0..55e78a1ade 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/DefaultCacheProvider.java @@ -20,11 +20,11 @@ public class DefaultCacheProvider private static final long serialVersionUID = 1L; /** - * Supplier of cache instance to be used by {@link DeserializerCache}. + * Cache instance to be used by {@link DeserializerCache}. */ - protected final Supplier>> _deserializerCacheSupplier; + protected final LookupCache> _deserializerCacheSupplier; - protected DefaultCacheProvider(Supplier>> deserializerCache) + protected DefaultCacheProvider(LookupCache> deserializerCache) { _deserializerCacheSupplier = deserializerCache; } @@ -37,7 +37,7 @@ protected DefaultCacheProvider(Supplier> provideDeserializerCache() { - return _deserializerCacheSupplier.get(); + return _deserializerCacheSupplier; } /* @@ -59,16 +59,16 @@ public static class Builder { /** * Supplier of cache instance to be used by {@link DeserializerCache}. */ - private Supplier>> _deserializerCacheSupplier; + private LookupCache> _deserializerCache; protected Builder() { } public DefaultCacheProvider build() { - return new DefaultCacheProvider(_deserializerCacheSupplier); + return new DefaultCacheProvider(_deserializerCache); } - public Builder deserializerCache(Supplier>> deserializerCache) { - _deserializerCacheSupplier = deserializerCache; + public Builder deserializerCache(LookupCache> deserializerCache) { + _deserializerCache = deserializerCache; return this; } } diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 65581ed626..fb98810247 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -253,8 +253,7 @@ protected DeserializationContext(DeserializationContext src) { _readCapabilities = src._readCapabilities; _view = src._view; _injectableValues = null; - _cache = (src._config == null) ? new DeserializerCache() - : new DeserializerCache(src._config.getCacheProvider()); + _cache = (src._cache == null) ? new DeserializerCache() : src._cache; } /** diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 527dcd1c8f..9780b277db 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -65,7 +65,7 @@ public void clear() { @Test public void testCacheConfig() throws Exception { DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .deserializerCache(() -> new SimpleTestCache()) + .deserializerCache(new SimpleTestCache()) .build(); ObjectMapper mapper = JsonMapper.builder() .cacheProvider(cacheProvider).build(); From ee5e2e2a94769012beb8c2f2a3cd2d6366543c2d Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 11:43:52 +0900 Subject: [PATCH 15/53] Adapt to DeserCache changes --- .../databind/deser/DefaultDeserializationContext.java | 2 +- .../jackson/databind/deser/DeserializerCache.java | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 0bd88cb450..6170c37ea8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -440,7 +440,7 @@ public DefaultDeserializationContext with(DeserializerFactory factory) { @Override public DefaultDeserializationContext withCacheProvider(CacheProvider cacheProvider) { - return new Impl(this, new DeserializerCache(cacheProvider)); + return new Impl(this, new DeserializerCache(cacheProvider.provideDeserializerCache())); } } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index b246a9708e..352c6d9851 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -34,8 +34,6 @@ public final class DeserializerCache * We will also cache some dynamically constructed deserializers; * specifically, ones that are expensive to construct. * This currently means bean, Enum and container deserializers. - *

- * Since 2.16, changed its type from {@link LRUMap} to {@link LookupCache} */ protected final LookupCache> _cachedDeserializers; @@ -68,13 +66,6 @@ public DeserializerCache(LookupCache> cache) _cachedDeserializers = cache; } - /** - * @since 2.16 - */ - public DeserializerCache(CacheProvider cacheProvider) { - _cachedDeserializers = cacheProvider.provideDeserializerCache(); - } - /* /********************************************************** /* JDK serialization handling From 73414ca4244d1fe8ecf07823b16b20cf32af1e87 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 21:47:27 +0900 Subject: [PATCH 16/53] WIP apply review --- .../databind/DeserializationConfig.java | 52 ------------------ .../jackson/databind/ObjectMapper.java | 9 ++-- .../jackson/databind/SerializationConfig.java | 7 +++ .../jackson/databind/cfg/BaseSettings.java | 54 +++++++++++++++++-- .../databind/cfg/DefaultCacheProvider.java | 4 ++ .../databind/deser/DeserializerCache.java | 14 ++++- 6 files changed, 78 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index a0d6cdc765..b16183776a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -101,13 +101,6 @@ public final class DeserializationConfig */ protected final int _formatReadFeaturesToChange; - /** - * Used to provide custom cache implementation in downstream components. - * - * @since 2.16 - */ - protected final CacheProvider _cacheProvider; - /* /********************************************************** /* Life-cycle, primary constructors for new instances @@ -134,7 +127,6 @@ public DeserializationConfig(BaseSettings base, _parserFeaturesToChange = 0; _formatReadFeatures = 0; _formatReadFeaturesToChange = 0; - _cacheProvider = null; } /** @@ -157,7 +149,6 @@ protected DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } /* @@ -182,7 +173,6 @@ private DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = parserFeatureMask; _formatReadFeatures = formatFeatures; _formatReadFeaturesToChange = formatFeatureMask; - _cacheProvider = src._cacheProvider; } /** @@ -201,7 +191,6 @@ private DeserializationConfig(DeserializationConfig src, SubtypeResolver str) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, BaseSettings base) @@ -216,7 +205,6 @@ private DeserializationConfig(DeserializationConfig src, BaseSettings base) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, JsonNodeFactory f) @@ -231,7 +219,6 @@ private DeserializationConfig(DeserializationConfig src, JsonNodeFactory f) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } // @since 2.12 @@ -247,7 +234,6 @@ private DeserializationConfig(DeserializationConfig src, ConstructorDetector cto _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, @@ -263,7 +249,6 @@ private DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, PropertyName rootName) @@ -278,7 +263,6 @@ private DeserializationConfig(DeserializationConfig src, PropertyName rootName) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } private DeserializationConfig(DeserializationConfig src, Class view) @@ -293,7 +277,6 @@ private DeserializationConfig(DeserializationConfig src, Class view) _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } protected DeserializationConfig(DeserializationConfig src, ContextAttributes attrs) @@ -308,7 +291,6 @@ protected DeserializationConfig(DeserializationConfig src, ContextAttributes att _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } protected DeserializationConfig(DeserializationConfig src, SimpleMixInResolver mixins) @@ -323,7 +305,6 @@ protected DeserializationConfig(DeserializationConfig src, SimpleMixInResolver m _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; } /** @@ -342,24 +323,6 @@ protected DeserializationConfig(DeserializationConfig src, _parserFeaturesToChange = src._parserFeaturesToChange; _formatReadFeatures = src._formatReadFeatures; _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = src._cacheProvider; - } - - /** - * @since 2.16 - */ - protected DeserializationConfig(DeserializationConfig src, CacheProvider cacheProvider) { - super(src); - _deserFeatures = src._deserFeatures; - _problemHandlers = src._problemHandlers; - _nodeFactory = src._nodeFactory; - _coercionConfigs = src._coercionConfigs; - _ctorDetector = src._ctorDetector; - _parserFeatures = src._parserFeatures; - _parserFeaturesToChange = src._parserFeaturesToChange; - _formatReadFeatures = src._formatReadFeatures; - _formatReadFeaturesToChange = src._formatReadFeaturesToChange; - _cacheProvider = cacheProvider; } // for unit tests only: @@ -959,13 +922,6 @@ public ConstructorDetector getConstructorDetector() { return _ctorDetector; } - /** - * @since 2.16 - */ - public CacheProvider getCacheProvider() { - return _cacheProvider; - } - /* /********************************************************** /* Introspection methods @@ -1090,12 +1046,4 @@ public CoercionAction findCoercionFromBlankString(LogicalType targetType, return _coercionConfigs.findCoercionFromBlankString(this, targetType, targetClass, actionIfBlankNotAllowed); } - - /** - * @return New instance of {@link DeserializationConfig} with configured {@link CacheProvider}. - * @since 2.16 - */ - public DeserializationConfig withCacheProvider(CacheProvider cacheProvider) { - return (cacheProvider == _cacheProvider) ? this : new DeserializationConfig(this, cacheProvider); - } } diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index c672c51763..37a7a1490b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2273,9 +2273,12 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { * @since 2.16 */ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { - _deserializationConfig = _deserializationConfig.withCacheProvider(cacheProvider); - _deserializationContext = _deserializationContext.withCacheProvider(cacheProvider); - // TODO: implement also serialization side + BaseSettings ds = _deserializationConfig.getBaseSettings().with(cacheProvider); + _deserializationConfig = _deserializationConfig._withBase(ds); + + BaseSettings ss = _serializationConfig.getBaseSettings().with(cacheProvider); + _serializationConfig = _serializationConfig._withBase(ss); + return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java index a710d51ab8..f0e216f532 100644 --- a/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java @@ -299,6 +299,13 @@ protected SerializationConfig(SerializationConfig src, DatatypeFeatures dtFeatur _formatWriteFeaturesToChange = src._formatWriteFeaturesToChange; } + /** + * @since 2.16 + */ + protected BaseSettings getBaseSettings() { + return _base; + } + /* /********************************************************** /* Life-cycle, factory methods from MapperConfig(Base) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java b/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java index 6a2b0d6b3d..fa86b1f437 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java @@ -143,6 +143,13 @@ public final class BaseSettings */ protected final Base64Variant _defaultBase64; + /** + * Used to provide custom cache implementation in downstream components. + * + * @since 2.16 + */ + protected final CacheProvider _cacheProvider; + /* /********************************************************** /* Construction @@ -150,13 +157,14 @@ public final class BaseSettings */ /** - * @since 2.12 + * @since 2.16 */ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, - PropertyNamingStrategy pns, TypeFactory tf, - TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, - Locale locale, TimeZone tz, Base64Variant defaultBase64, - PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming) + PropertyNamingStrategy pns, TypeFactory tf, + TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, + Locale locale, TimeZone tz, Base64Variant defaultBase64, + PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming, + CacheProvider cacheProvider) { _classIntrospector = ci; _annotationIntrospector = ai; @@ -170,6 +178,20 @@ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, _defaultBase64 = defaultBase64; _typeValidator = ptv; _accessorNaming = accNaming; + _cacheProvider = cacheProvider; + } + + /** + * @since 2.12 + */ + public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, + PropertyNamingStrategy pns, TypeFactory tf, + TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, + Locale locale, TimeZone tz, Base64Variant defaultBase64, + PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming) + { + this(ci, ai, pns, tf, typer, dateFormat, hi, locale, tz, defaultBase64, ptv, accNaming, + DefaultCacheProvider.defaultInstance()); } @Deprecated // since 2.12 @@ -364,6 +386,21 @@ public BaseSettings with(PolymorphicTypeValidator v) { _timeZone, _defaultBase64, v, _accessorNaming); } + /** + * @return New instance of {@link BaseSettings} with configured {@link CacheProvider}. + * + * @since 2.16 + */ + public BaseSettings with(CacheProvider cacheProvider) { + if (cacheProvider == _cacheProvider) { + return this; + } + return new BaseSettings(_classIntrospector, _annotationIntrospector, + _propertyNamingStrategy, _typeFactory, + _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, cacheProvider); + } + /* /********************************************************** /* API @@ -432,6 +469,13 @@ public boolean hasExplicitTimeZone() { public Base64Variant getBase64Variant() { return _defaultBase64; } + + /** + * @since 2.16 + */ + public CacheProvider getCacheProvider() { + return _cacheProvider; + } /* /********************************************************** diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 686fc71d3a..fea9c11e91 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -28,6 +28,10 @@ protected DefaultCacheProvider(LookupCache> d { _deserializerCacheSupplier = deserializerCache; } + + public static CacheProvider defaultInstance() { + return new DefaultCacheProvider(DeserializerCache.defaultSizedCache()); + } /* /********************************************************** diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 352c6d9851..62c97b3f7a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -23,6 +23,8 @@ public final class DeserializerCache implements java.io.Serializable // since 2.1 { private static final long serialVersionUID = 1L; + + public final static int MAX_SIZE = 2000; /* /********************************************************** @@ -52,11 +54,19 @@ public final class DeserializerCache */ public DeserializerCache() { - this(2000); // see [databind#1995] + this(MAX_SIZE); // see [databind#1995] } public DeserializerCache(int maxSize) { - this(new LRUMap<>(Math.min(64, maxSize>>2), maxSize)); + this(defaultCache(maxSize)); + } + + public static LookupCache> defaultSizedCache() { + return new LRUMap<>(Math.min(64, MAX_SIZE >>2), MAX_SIZE); + } + + public static LookupCache> defaultCache(int maxSize) { + return new LRUMap<>(Math.min(64, maxSize>>2), maxSize); } /** From 11bd54ab30b8f76a82ff64808ed2ed6f0a4912c9 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 21:59:59 +0900 Subject: [PATCH 17/53] Add CacheProvider configuration in BaseSettings --- .../jackson/databind/ObjectMapper.java | 4 +- .../jackson/databind/cfg/BaseSettings.java | 80 +++++++++++++++---- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index f1057ccc24..cecad79cc2 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -389,7 +389,9 @@ public boolean useForType(JavaType t) // Only for 2.x; 3.x will use more restrictive default LaissezFaireSubTypeValidator.instance, // Since 2.12: - new DefaultAccessorNamingStrategy.Provider() + new DefaultAccessorNamingStrategy.Provider(), + // Since 2.16: [databind#2502] Add a way to configure Caches Jackson uses + DefaultCacheProvider.defaultInstance() ); /* diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java b/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java index 6a2b0d6b3d..de46bdeb24 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java @@ -143,6 +143,13 @@ public final class BaseSettings */ protected final Base64Variant _defaultBase64; + /** + * Used to provide custom cache implementation in downstream components. + * + * @since 2.16 + */ + protected final CacheProvider _cacheProvider; + /* /********************************************************** /* Construction @@ -150,13 +157,14 @@ public final class BaseSettings */ /** - * @since 2.12 + * @since 2.16 */ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, PropertyNamingStrategy pns, TypeFactory tf, TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, Locale locale, TimeZone tz, Base64Variant defaultBase64, - PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming) + PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming, + CacheProvider cacheProvider) { _classIntrospector = ci; _annotationIntrospector = ai; @@ -170,6 +178,22 @@ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, _defaultBase64 = defaultBase64; _typeValidator = ptv; _accessorNaming = accNaming; + _cacheProvider = cacheProvider; + } + + /** + * @since 2.12 + * @deprecated Since 2.16, use variant that takes {@link CacheProvider} instead. + */ + @Deprecated + public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, + PropertyNamingStrategy pns, TypeFactory tf, + TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, + Locale locale, TimeZone tz, Base64Variant defaultBase64, + PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming) + { + this(ci, ai, pns, tf, typer, dateFormat, hi, locale, tz, defaultBase64, ptv, accNaming, + DefaultCacheProvider.defaultInstance()); } @Deprecated // since 2.12 @@ -180,7 +204,7 @@ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, PolymorphicTypeValidator ptv) { this(ci, ai, pns, tf, typer, dateFormat, hi, locale, tz, defaultBase64, ptv, - new DefaultAccessorNamingStrategy.Provider()); + new DefaultAccessorNamingStrategy.Provider(), DefaultCacheProvider.defaultInstance()); } /** @@ -201,7 +225,8 @@ public BaseSettings copy() { _timeZone, _defaultBase64, _typeValidator, - _accessorNaming); + _accessorNaming, + _cacheProvider); } /* @@ -216,7 +241,7 @@ public BaseSettings withClassIntrospector(ClassIntrospector ci) { } return new BaseSettings(ci, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withAnnotationIntrospector(AnnotationIntrospector ai) { @@ -225,7 +250,7 @@ public BaseSettings withAnnotationIntrospector(AnnotationIntrospector ai) { } return new BaseSettings(_classIntrospector, ai, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withInsertedAnnotationIntrospector(AnnotationIntrospector ai) { @@ -252,7 +277,7 @@ public BaseSettings withPropertyNamingStrategy(PropertyNamingStrategy pns) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, pns, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } // @since 2.12 @@ -262,7 +287,7 @@ public BaseSettings withAccessorNaming(AccessorNamingStrategy.Provider p) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, p); + _timeZone, _defaultBase64, _typeValidator, p, _cacheProvider); } public BaseSettings withTypeFactory(TypeFactory tf) { @@ -271,7 +296,7 @@ public BaseSettings withTypeFactory(TypeFactory tf) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, tf, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withTypeResolverBuilder(TypeResolverBuilder typer) { @@ -280,7 +305,7 @@ public BaseSettings withTypeResolverBuilder(TypeResolverBuilder typer) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, typer, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withDateFormat(DateFormat df) { @@ -294,7 +319,7 @@ public BaseSettings withDateFormat(DateFormat df) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, df, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withHandlerInstantiator(HandlerInstantiator hi) { @@ -303,7 +328,7 @@ public BaseSettings withHandlerInstantiator(HandlerInstantiator hi) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, hi, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings with(Locale l) { @@ -312,7 +337,7 @@ public BaseSettings with(Locale l) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, l, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } /** @@ -335,7 +360,7 @@ public BaseSettings with(TimeZone tz) return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, df, _handlerInstantiator, _locale, - tz, _defaultBase64, _typeValidator, _accessorNaming); + tz, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } /** @@ -348,7 +373,7 @@ public BaseSettings with(Base64Variant base64) { return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, base64, _typeValidator, _accessorNaming); + _timeZone, base64, _typeValidator, _accessorNaming, _cacheProvider); } /** @@ -361,7 +386,23 @@ public BaseSettings with(PolymorphicTypeValidator v) { return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, v, _accessorNaming); + _timeZone, _defaultBase64, v, _accessorNaming, _cacheProvider); + } + + /** + * Fluent factory for constructing a new instance with provided {@link CacheProvider}. + * + * @return a new instance with provided {@link CacheProvider}. + * @since 2.16 + */ + public BaseSettings with(CacheProvider cacheProvider) { + if (cacheProvider == _cacheProvider) { + return this; + } + return new BaseSettings(_classIntrospector, _annotationIntrospector, + _propertyNamingStrategy, _typeFactory, + _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, cacheProvider); } /* @@ -432,6 +473,13 @@ public boolean hasExplicitTimeZone() { public Base64Variant getBase64Variant() { return _defaultBase64; } + + /** + * @since 2.16 + */ + public CacheProvider getCacheProvider() { + return _cacheProvider; + } /* /********************************************************** From c9e7cd17d37dc91f546a80790c954fda031edffe Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 22:10:30 +0900 Subject: [PATCH 18/53] Update ObjectMapper.java --- .../com/fasterxml/jackson/databind/ObjectMapper.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 37a7a1490b..e7e948508f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2273,12 +2273,9 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { * @since 2.16 */ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { - BaseSettings ds = _deserializationConfig.getBaseSettings().with(cacheProvider); - _deserializationConfig = _deserializationConfig._withBase(ds); - - BaseSettings ss = _serializationConfig.getBaseSettings().with(cacheProvider); - _serializationConfig = _serializationConfig._withBase(ss); - + _deserializationConfig.getBaseSettings().with(cacheProvider); + BaseSettings s = _deserializationConfig.getBaseSettings().with(); + _deserializationConfig = _deserializationConfig._withBase(s); return this; } From 465cc51481a2347ae8c4bdba0b725882ed7f555e Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 21:59:59 +0900 Subject: [PATCH 19/53] Add CacheProvider configuration in BaseSettings --- .../jackson/databind/ObjectMapper.java | 4 +- .../jackson/databind/cfg/BaseSettings.java | 44 ++++++++++--------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index e7e948508f..90147b7551 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -389,7 +389,9 @@ public boolean useForType(JavaType t) // Only for 2.x; 3.x will use more restrictive default LaissezFaireSubTypeValidator.instance, // Since 2.12: - new DefaultAccessorNamingStrategy.Provider() + new DefaultAccessorNamingStrategy.Provider(), + // Since 2.16: [databind#2502] Add a way to configure Caches Jackson uses + DefaultCacheProvider.defaultInstance() ); /* diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java b/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java index fa86b1f437..de46bdeb24 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/BaseSettings.java @@ -160,11 +160,11 @@ public final class BaseSettings * @since 2.16 */ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, - PropertyNamingStrategy pns, TypeFactory tf, - TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, - Locale locale, TimeZone tz, Base64Variant defaultBase64, - PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming, - CacheProvider cacheProvider) + PropertyNamingStrategy pns, TypeFactory tf, + TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, + Locale locale, TimeZone tz, Base64Variant defaultBase64, + PolymorphicTypeValidator ptv, AccessorNamingStrategy.Provider accNaming, + CacheProvider cacheProvider) { _classIntrospector = ci; _annotationIntrospector = ai; @@ -183,7 +183,9 @@ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, /** * @since 2.12 + * @deprecated Since 2.16, use variant that takes {@link CacheProvider} instead. */ + @Deprecated public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, PropertyNamingStrategy pns, TypeFactory tf, TypeResolverBuilder typer, DateFormat dateFormat, HandlerInstantiator hi, @@ -202,7 +204,7 @@ public BaseSettings(ClassIntrospector ci, AnnotationIntrospector ai, PolymorphicTypeValidator ptv) { this(ci, ai, pns, tf, typer, dateFormat, hi, locale, tz, defaultBase64, ptv, - new DefaultAccessorNamingStrategy.Provider()); + new DefaultAccessorNamingStrategy.Provider(), DefaultCacheProvider.defaultInstance()); } /** @@ -223,7 +225,8 @@ public BaseSettings copy() { _timeZone, _defaultBase64, _typeValidator, - _accessorNaming); + _accessorNaming, + _cacheProvider); } /* @@ -238,7 +241,7 @@ public BaseSettings withClassIntrospector(ClassIntrospector ci) { } return new BaseSettings(ci, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withAnnotationIntrospector(AnnotationIntrospector ai) { @@ -247,7 +250,7 @@ public BaseSettings withAnnotationIntrospector(AnnotationIntrospector ai) { } return new BaseSettings(_classIntrospector, ai, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withInsertedAnnotationIntrospector(AnnotationIntrospector ai) { @@ -274,7 +277,7 @@ public BaseSettings withPropertyNamingStrategy(PropertyNamingStrategy pns) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, pns, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } // @since 2.12 @@ -284,7 +287,7 @@ public BaseSettings withAccessorNaming(AccessorNamingStrategy.Provider p) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, p); + _timeZone, _defaultBase64, _typeValidator, p, _cacheProvider); } public BaseSettings withTypeFactory(TypeFactory tf) { @@ -293,7 +296,7 @@ public BaseSettings withTypeFactory(TypeFactory tf) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, tf, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withTypeResolverBuilder(TypeResolverBuilder typer) { @@ -302,7 +305,7 @@ public BaseSettings withTypeResolverBuilder(TypeResolverBuilder typer) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, typer, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withDateFormat(DateFormat df) { @@ -316,7 +319,7 @@ public BaseSettings withDateFormat(DateFormat df) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, df, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings withHandlerInstantiator(HandlerInstantiator hi) { @@ -325,7 +328,7 @@ public BaseSettings withHandlerInstantiator(HandlerInstantiator hi) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, hi, _locale, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } public BaseSettings with(Locale l) { @@ -334,7 +337,7 @@ public BaseSettings with(Locale l) { } return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, l, - _timeZone, _defaultBase64, _typeValidator, _accessorNaming); + _timeZone, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } /** @@ -357,7 +360,7 @@ public BaseSettings with(TimeZone tz) return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, df, _handlerInstantiator, _locale, - tz, _defaultBase64, _typeValidator, _accessorNaming); + tz, _defaultBase64, _typeValidator, _accessorNaming, _cacheProvider); } /** @@ -370,7 +373,7 @@ public BaseSettings with(Base64Variant base64) { return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, base64, _typeValidator, _accessorNaming); + _timeZone, base64, _typeValidator, _accessorNaming, _cacheProvider); } /** @@ -383,12 +386,13 @@ public BaseSettings with(PolymorphicTypeValidator v) { return new BaseSettings(_classIntrospector, _annotationIntrospector, _propertyNamingStrategy, _typeFactory, _typeResolverBuilder, _dateFormat, _handlerInstantiator, _locale, - _timeZone, _defaultBase64, v, _accessorNaming); + _timeZone, _defaultBase64, v, _accessorNaming, _cacheProvider); } /** - * @return New instance of {@link BaseSettings} with configured {@link CacheProvider}. + * Fluent factory for constructing a new instance with provided {@link CacheProvider}. * + * @return a new instance with provided {@link CacheProvider}. * @since 2.16 */ public BaseSettings with(CacheProvider cacheProvider) { From 05c1d792f5dd58b478f3819d384975de08064450 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 22:14:32 +0900 Subject: [PATCH 20/53] Add `BaseSettings` --- .../com/fasterxml/jackson/databind/ObjectMapper.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 90147b7551..baf443a6ae 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2275,9 +2275,12 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { * @since 2.16 */ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { - _deserializationConfig.getBaseSettings().with(cacheProvider); - BaseSettings s = _deserializationConfig.getBaseSettings().with(); - _deserializationConfig = _deserializationConfig._withBase(s); + BaseSettings d = _deserializationConfig.getBaseSettings().with(cacheProvider); + _deserializationConfig = _deserializationConfig._withBase(d); + + BaseSettings s = _serializationConfig.getBaseSettings().with(cacheProvider); + _serializationConfig = _serializationConfig._withBase(s); + return this; } From 890f416df87794bc8885277aa8a697287cef0677 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 22:20:20 +0900 Subject: [PATCH 21/53] Add BaseSettings `ObjectMapper.setCacheProvider(CacheProvider cacheProvider)` --- .../fasterxml/jackson/databind/DeserializationConfig.java | 1 - .../java/com/fasterxml/jackson/databind/ObjectMapper.java | 5 ++++- .../com/fasterxml/jackson/databind/SerializationConfig.java | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java index b16183776a..015a242049 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java @@ -325,7 +325,6 @@ protected DeserializationConfig(DeserializationConfig src, _formatReadFeaturesToChange = src._formatReadFeaturesToChange; } - // for unit tests only: protected BaseSettings getBaseSettings() { return _base; } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index cecad79cc2..2977221c13 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2275,7 +2275,10 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { * @since 2.16 */ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { - // to implement + BaseSettings forDeser = _deserializationConfig.getBaseSettings().with(cacheProvider); + BaseSettings forSer = _serializationConfig.getBaseSettings().with(cacheProvider); + _deserializationConfig = _deserializationConfig._withBase(forDeser); + _serializationConfig = _serializationConfig._withBase(forSer); return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java index a710d51ab8..3bdc008f7d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java @@ -299,6 +299,11 @@ protected SerializationConfig(SerializationConfig src, DatatypeFeatures dtFeatur _formatWriteFeaturesToChange = src._formatWriteFeaturesToChange; } + /** + * @since 2.16 + */ + protected BaseSettings getBaseSettings() { return _base; } + /* /********************************************************** /* Life-cycle, factory methods from MapperConfig(Base) From 6f0cd81f29ff67ecf9f8fd6f937d047d502fe765 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 22:36:05 +0900 Subject: [PATCH 22/53] Remove supplier --- .../jackson/databind/cfg/DefaultCacheProvider.java | 10 +++++----- .../jackson/databind/deser/DeserializerCache.java | 8 ++------ 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index fea9c11e91..1609fd3765 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -22,15 +22,15 @@ public class DefaultCacheProvider /** * Cache instance to be used by {@link DeserializerCache}. */ - protected final LookupCache> _deserializerCacheSupplier; + protected final LookupCache> _deserializerCache; protected DefaultCacheProvider(LookupCache> deserializerCache) { - _deserializerCacheSupplier = deserializerCache; + _deserializerCache = deserializerCache; } public static CacheProvider defaultInstance() { - return new DefaultCacheProvider(DeserializerCache.defaultSizedCache()); + return new DefaultCacheProvider(DeserializerCache.defaultCache()); } /* @@ -41,7 +41,7 @@ public static CacheProvider defaultInstance() { @Override public LookupCache> provideDeserializerCache() { - return _deserializerCacheSupplier; + return _deserializerCache; } /* @@ -58,7 +58,7 @@ public static DefaultCacheProvider.Builder builder() { * Builder class to construct {@link DefaultCacheProvider} instance * and to keep {@link DefaultCacheProvider} immutable. */ - public static class Builder { + protected static class Builder { /** * Supplier of cache instance to be used by {@link DeserializerCache}. diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 62c97b3f7a..737292dd7a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -58,17 +58,13 @@ public DeserializerCache() { } public DeserializerCache(int maxSize) { - this(defaultCache(maxSize)); + this(new LRUMap<>(Math.min(64, maxSize>>2), maxSize)); } - public static LookupCache> defaultSizedCache() { + public static LookupCache> defaultCache() { return new LRUMap<>(Math.min(64, MAX_SIZE >>2), MAX_SIZE); } - public static LookupCache> defaultCache(int maxSize) { - return new LRUMap<>(Math.min(64, maxSize>>2), maxSize); - } - /** * @since 2.16 */ From 447df549fe20b4bb17f5594a9a81d09663375e68 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 22:53:21 +0900 Subject: [PATCH 23/53] Implement CacheProvider, its default, and related DeserializerCache --- .../jackson/databind/cfg/CacheProvider.java | 13 +++- .../databind/cfg/DefaultCacheProvider.java | 77 ++++++++++++++++++- .../databind/deser/DeserializerCache.java | 19 ++++- 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java index d9cebf5964..78b697f331 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java @@ -1,5 +1,10 @@ package com.fasterxml.jackson.databind.cfg; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.deser.DeserializerCache; +import com.fasterxml.jackson.databind.util.LookupCache; + /** * Interface that defines API Jackson uses for constructing various internal * caches. This allows configuring custom caches and cache configurations. @@ -11,5 +16,11 @@ public interface CacheProvider extends java.io.Serializable { - // !!! TODO: add methods + /** + * Method to provide a {@link LookupCache} instance for {@link DeserializerCache} + * + * @return {@link LookupCache} instance for caching {@link JsonDeserializer}s + */ + LookupCache> provideForDeserializerCache(); + } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 9b16755383..d29fabd675 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -1,7 +1,15 @@ package com.fasterxml.jackson.databind.cfg; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.deser.DeserializerCache; +import com.fasterxml.jackson.databind.util.LookupCache; + /** * Default implementation of {@link CacheProvider}. + * Provides builder-based custom cache configuration using {@link DefaultCacheProvider.Builder}. + *

+ * Users can either use {@link DefaultCacheProvider.Builder} or write their own {@link CacheProvider} imlementation. * * @since 2.16 */ @@ -10,10 +18,73 @@ public class DefaultCacheProvider { private static final long serialVersionUID = 1L; - public static DefaultCacheProvider defaultInstance() { - return new DefaultCacheProvider(); + /** + * Cache instance to be used by {@link DeserializerCache}. + */ + protected final LookupCache> _deserializerCache; + + /* + /********************************************************************** + /* Life cycle + /********************************************************************** + */ + + protected DefaultCacheProvider(LookupCache> deserializerCache) + { + _deserializerCache = deserializerCache; } - // To implement! + /* + /********************************************************************** + /* Defaults + /********************************************************************** + */ + + public static CacheProvider defaultInstance() { + return new DefaultCacheProvider(DeserializerCache.defaultCache()); + } + + /* + /********************************************************** + /* Cache accessors + /********************************************************** + */ + + @Override + public LookupCache> provideForDeserializerCache() { + return _deserializerCache; + } + + /* + /********************************************************** + /* Configuration using Builder + /********************************************************** + */ + + public static DefaultCacheProvider.Builder builder() { + return new Builder(); + } + /** + * Builder class to construct {@link DefaultCacheProvider} instance + * and to keep {@link DefaultCacheProvider} immutable. + */ + protected static class Builder { + + /** + * Supplier of cache instance to be used by {@link DeserializerCache}. + */ + private LookupCache> _deserializerCache; + + protected Builder() { } + + public DefaultCacheProvider build() { + return new DefaultCacheProvider(_deserializerCache); + } + + public Builder deserializerCache(LookupCache> deserializerCache) { + _deserializerCache = deserializerCache; + return this; + } + } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 352c6d9851..224dd41ab6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.DefaultCacheProvider; import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.type.*; @@ -24,6 +25,13 @@ public final class DeserializerCache { private static final long serialVersionUID = 1L; + /** + * Declared as field since 2.16, used to be passed inline in {@link #DeserializerCache(int)}. + * + * @since 2.16 + */ + public final static int MAX_CACHE_SIZE = 2000; + /* /********************************************************** /* Caching @@ -52,7 +60,7 @@ public final class DeserializerCache */ public DeserializerCache() { - this(2000); // see [databind#1995] + this(MAX_CACHE_SIZE); // see [databind#1995] } public DeserializerCache(int maxSize) { @@ -111,6 +119,15 @@ public void flushCachedDeserializers() { _cachedDeserializers.clear(); } + /** + * Method used to provide cache instance for {@link DefaultCacheProvider#defaultInstance()}. + * + * @since 2.16 + */ + public static LookupCache> defaultCache() { + return new LRUMap<>(Math.min(64, MAX_CACHE_SIZE >>2), MAX_CACHE_SIZE); + } + /* /********************************************************** /* General deserializer locating method From 3e371c9eed2d02d484398042f35b64c0cc48f063 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 22:53:21 +0900 Subject: [PATCH 24/53] Implement CacheProvider, its default, and related DeserializerCache --- .../jackson/databind/cfg/CacheProvider.java | 3 +-- .../databind/cfg/DefaultCacheProvider.java | 21 ++++++++++++---- .../databind/deser/DeserializerCache.java | 25 +++++++++++++------ 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java index 4249345129..6690b4599a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java @@ -15,12 +15,11 @@ public interface CacheProvider extends java.io.Serializable { - /** * Method to provide a {@link LookupCache} instance for {@link DeserializerCache} * * @return {@link LookupCache} instance for caching {@link JsonDeserializer}s */ - LookupCache> provideDeserializerCache(); + LookupCache> provideForDeserializerCache(); } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 1609fd3765..d29fabd675 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -6,28 +6,39 @@ import com.fasterxml.jackson.databind.util.LookupCache; /** - * Default implementation of {@link CacheProvider} that provides easy, builder-based custom cache configuration - * using {@link DefaultCacheProvider.Builder}. + * Default implementation of {@link CacheProvider}. + * Provides builder-based custom cache configuration using {@link DefaultCacheProvider.Builder}. *

- * Users can either use this class or implement their own {@link CacheProvider} imlementation. + * Users can either use {@link DefaultCacheProvider.Builder} or write their own {@link CacheProvider} imlementation. * * @since 2.16 */ public class DefaultCacheProvider implements CacheProvider { - private static final long serialVersionUID = 1L; /** * Cache instance to be used by {@link DeserializerCache}. */ protected final LookupCache> _deserializerCache; + + /* + /********************************************************************** + /* Life cycle + /********************************************************************** + */ protected DefaultCacheProvider(LookupCache> deserializerCache) { _deserializerCache = deserializerCache; } + + /* + /********************************************************************** + /* Defaults + /********************************************************************** + */ public static CacheProvider defaultInstance() { return new DefaultCacheProvider(DeserializerCache.defaultCache()); @@ -40,7 +51,7 @@ public static CacheProvider defaultInstance() { */ @Override - public LookupCache> provideDeserializerCache() { + public LookupCache> provideForDeserializerCache() { return _deserializerCache; } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 737292dd7a..224dd41ab6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.DefaultCacheProvider; import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.type.*; @@ -23,8 +24,13 @@ public final class DeserializerCache implements java.io.Serializable // since 2.1 { private static final long serialVersionUID = 1L; - - public final static int MAX_SIZE = 2000; + + /** + * Declared as field since 2.16, used to be passed inline in {@link #DeserializerCache(int)}. + * + * @since 2.16 + */ + public final static int MAX_CACHE_SIZE = 2000; /* /********************************************************** @@ -54,17 +60,13 @@ public final class DeserializerCache */ public DeserializerCache() { - this(MAX_SIZE); // see [databind#1995] + this(MAX_CACHE_SIZE); // see [databind#1995] } public DeserializerCache(int maxSize) { this(new LRUMap<>(Math.min(64, maxSize>>2), maxSize)); } - public static LookupCache> defaultCache() { - return new LRUMap<>(Math.min(64, MAX_SIZE >>2), MAX_SIZE); - } - /** * @since 2.16 */ @@ -117,6 +119,15 @@ public void flushCachedDeserializers() { _cachedDeserializers.clear(); } + /** + * Method used to provide cache instance for {@link DefaultCacheProvider#defaultInstance()}. + * + * @since 2.16 + */ + public static LookupCache> defaultCache() { + return new LRUMap<>(Math.min(64, MAX_CACHE_SIZE >>2), MAX_CACHE_SIZE); + } + /* /********************************************************** /* General deserializer locating method From 49ffff04a61271fd249fe250db1edb2dd26d9979 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 22:59:14 +0900 Subject: [PATCH 25/53] Update DefaultDeserializationContext.java --- .../jackson/databind/deser/DefaultDeserializationContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index ff3e37a7fc..5b5085a9d0 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -441,7 +441,7 @@ public DefaultDeserializationContext with(DeserializerFactory factory) { @Override public DefaultDeserializationContext withCacheProvider(CacheProvider cacheProvider) { - return new Impl(this, new DeserializerCache(cacheProvider.provideDeserializerCache())); + return new Impl(this, new DeserializerCache(cacheProvider.provideForDeserializerCache())); } } } From 054d46ffd64a733e05e65ed0f7c6c9a661d0790a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Thu, 31 Aug 2023 23:00:42 +0900 Subject: [PATCH 26/53] Fix docs and naming --- .../jackson/databind/cfg/DefaultCacheProvider.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index d29fabd675..d738ae312c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -19,7 +19,7 @@ public class DefaultCacheProvider private static final long serialVersionUID = 1L; /** - * Cache instance to be used by {@link DeserializerCache}. + * Cache instance to provide for {@link DeserializerCache}. */ protected final LookupCache> _deserializerCache; @@ -69,11 +69,8 @@ public static DefaultCacheProvider.Builder builder() { * Builder class to construct {@link DefaultCacheProvider} instance * and to keep {@link DefaultCacheProvider} immutable. */ - protected static class Builder { - - /** - * Supplier of cache instance to be used by {@link DeserializerCache}. - */ + public static class Builder { + private LookupCache> _deserializerCache; protected Builder() { } From 8e229ec1bfe4a692ce1011f8aa00445f400cd46a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:00:36 +0900 Subject: [PATCH 27/53] Remove binding of CacheProv in DatabindContext --- .../jackson/databind/DatabindContext.java | 11 ----------- .../jackson/databind/DeserializationContext.java | 16 +--------------- .../jackson/databind/cfg/MapperConfig.java | 7 +++++++ .../jackson/databind/cfg/MapperConfigBase.java | 7 ++++++- 4 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java b/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java index c285aecee0..be2fd7d428 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DatabindContext.java @@ -5,7 +5,6 @@ import java.util.TimeZone; import com.fasterxml.jackson.annotation.*; -import com.fasterxml.jackson.databind.cfg.CacheProvider; import com.fasterxml.jackson.databind.cfg.DatatypeFeature; import com.fasterxml.jackson.databind.cfg.DatatypeFeatures; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; @@ -149,16 +148,6 @@ public abstract class DatabindContext */ public abstract DatabindContext setAttribute(Object key, Object value); - /** - * Method to configure a provider for custom cache implementations downstream. - * Should be overriden by sub-classes. - * - * @since 2.16 - */ - public DatabindContext withCacheProvider(CacheProvider cacheProvider) { - return this; - } - /* /********************************************************** /* Type instantiation/resolution diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index fb98810247..8cecc2be70 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -246,6 +246,7 @@ protected DeserializationContext(DeserializationContext src, * Copy-constructor for use with copy() by {@link ObjectMapper#copy()} */ protected DeserializationContext(DeserializationContext src) { + _cache = new DeserializerCache(); _factory = src._factory; _config = src._config; @@ -253,21 +254,6 @@ protected DeserializationContext(DeserializationContext src) { _readCapabilities = src._readCapabilities; _view = src._view; _injectableValues = null; - _cache = (src._cache == null) ? new DeserializerCache() : src._cache; - } - - /** - * @since 2.16 - */ - public DeserializationContext(DefaultDeserializationContext src, DeserializerCache deserializerCache) { - _factory = src._factory; - - _config = src._config; - _featureFlags = src._featureFlags; - _readCapabilities = src._readCapabilities; - _view = src._view; - _injectableValues = src._injectableValues; - _cache = deserializerCache; } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java index c274d4500b..5e97bcd9d6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java @@ -674,6 +674,13 @@ public Base64Variant getBase64Variant() { */ public abstract ContextAttributes getAttributes(); + /** + * Method for accessing configured {@link CacheProvider} via {@link MapperBuilder#cacheProvider(CacheProvider)}. + * + * @since 2.16 + */ + public abstract CacheProvider getCacheProvider(); + /** * @since 2.6 */ diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java index b954080469..6c3d83b2c7 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java @@ -874,7 +874,7 @@ public Boolean getDefaultMergeable(Class baseType) { } return _configOverrides.getDefaultMergeable(); } - + /* /********************************************************************** /* Other config access @@ -897,6 +897,11 @@ public PropertyName findRootName(Class rawRootType) { return _rootNames.findRootName(rawRootType, this); } + @Override // Since 2.16 + public CacheProvider getCacheProvider() { + return _base.getCacheProvider(); + } + /* /********************************************************************** /* ClassIntrospector.MixInResolver impl: From 6345e36731f4dbfb36c72efe8977b9bc7ec53ab4 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:01:36 +0900 Subject: [PATCH 28/53] Sync changes with sub-PRs Update CacheProvider.java --- .../fasterxml/jackson/databind/cfg/CacheProvider.java | 7 ++++--- .../jackson/databind/cfg/DefaultCacheProvider.java | 9 +++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java index 6690b4599a..78b697f331 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java @@ -6,14 +6,15 @@ import com.fasterxml.jackson.databind.util.LookupCache; /** - * Interface that defines API for custom Cache configuration that overrides default cache implementations used. + * Interface that defines API Jackson uses for constructing various internal + * caches. This allows configuring custom caches and cache configurations. * A {@link CacheProvider} instance will be configured through a builder such as * {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)} - * + * * @since 2.16 */ public interface CacheProvider - extends java.io.Serializable + extends java.io.Serializable { /** * Method to provide a {@link LookupCache} instance for {@link DeserializerCache} diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index d29fabd675..d738ae312c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -19,7 +19,7 @@ public class DefaultCacheProvider private static final long serialVersionUID = 1L; /** - * Cache instance to be used by {@link DeserializerCache}. + * Cache instance to provide for {@link DeserializerCache}. */ protected final LookupCache> _deserializerCache; @@ -69,11 +69,8 @@ public static DefaultCacheProvider.Builder builder() { * Builder class to construct {@link DefaultCacheProvider} instance * and to keep {@link DefaultCacheProvider} immutable. */ - protected static class Builder { - - /** - * Supplier of cache instance to be used by {@link DeserializerCache}. - */ + public static class Builder { + private LookupCache> _deserializerCache; protected Builder() { } From 578eda98d0cbf1f75de5f7d4dbfa146614bd140b Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:14:15 +0900 Subject: [PATCH 29/53] Minimize changes --- .../deser/DefaultDeserializationContext.java | 19 ------------------- .../ser/DefaultSerializerProvider.java | 7 ------- 2 files changed, 26 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 5b5085a9d0..0e57e3ccb0 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -11,7 +11,6 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.cfg.CacheProvider; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId; import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring; @@ -69,10 +68,6 @@ protected DefaultDeserializationContext(DefaultDeserializationContext src) { super(src); } - public DefaultDeserializationContext(DefaultDeserializationContext src, DeserializerCache deserializerCache) { - super(src, deserializerCache); - } - /** * Method needed to ensure that {@link ObjectMapper#copy} will work * properly; specifically, that caches are cleared, but settings @@ -85,11 +80,6 @@ public DefaultDeserializationContext copy() { throw new IllegalStateException("DefaultDeserializationContext sub-class not overriding copy()"); } - @Override - public DefaultDeserializationContext withCacheProvider(CacheProvider cacheProvider) { - throw new IllegalStateException("DefaultDeserializationContext sub-class not overriding withCacheProvider(CacheProvider)"); - } - /* /********************************************************** /* Abstract methods impls, Object Id @@ -412,10 +402,6 @@ private Impl(Impl src, DeserializationConfig config) { super(src, config); } - private Impl(Impl src, DeserializerCache cache) { - super(src, cache); - } - @Override public DefaultDeserializationContext copy() { ClassUtil.verifyMustOverride(Impl.class, this, "copy"); @@ -438,10 +424,5 @@ public DefaultDeserializationContext createDummyInstance(DeserializationConfig c public DefaultDeserializationContext with(DeserializerFactory factory) { return new Impl(this, factory); } - - @Override - public DefaultDeserializationContext withCacheProvider(CacheProvider cacheProvider) { - return new Impl(this, new DeserializerCache(cacheProvider.provideForDeserializerCache())); - } } } diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java b/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java index 8836f6cebc..8d029c5def 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/DefaultSerializerProvider.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.annotation.ObjectIdGenerator; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.cfg.CacheProvider; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; @@ -625,11 +624,5 @@ public DefaultSerializerProvider copy() public Impl createInstance(SerializationConfig config, SerializerFactory jsf) { return new Impl(this, config, jsf); } - - @Override - public Impl withCacheProvider(CacheProvider cacheProvider) { - // TODO: implement like {@code DefaultDeserializationContext.Impl#withCacheProvider} - return this; - } } } From f3600db5c8f5825ca7b84eb186ca14b060a28088 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:18:42 +0900 Subject: [PATCH 30/53] Minor code reuse and access control in DefaultCache. --- .../databind/deser/DeserializerCache.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 224dd41ab6..9157488361 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -26,11 +26,12 @@ public final class DeserializerCache private static final long serialVersionUID = 1L; /** - * Declared as field since 2.16, used to be passed inline in {@link #DeserializerCache(int)}. + * Previously was passed inline in {@link #DeserializerCache(int)}. + * Declared as field since 2.16. * * @since 2.16 */ - public final static int MAX_CACHE_SIZE = 2000; + private final static int MAX_CACHE_SIZE = 2000; /* /********************************************************** @@ -64,7 +65,7 @@ public DeserializerCache() { } public DeserializerCache(int maxSize) { - this(new LRUMap<>(Math.min(64, maxSize>>2), maxSize)); + this(_createCache(maxSize)); } /** @@ -74,6 +75,15 @@ public DeserializerCache(LookupCache> cache) _cachedDeserializers = cache; } + /** + * Internal method to create actual cache instance for {@link #_cachedDeserializers} + * + * @since 2.16 + */ + private static LookupCache> _createCache(int maxSize) { + return new LRUMap<>(Math.min(64, maxSize>>2), maxSize); + } + /* /********************************************************** /* JDK serialization handling @@ -120,12 +130,13 @@ public void flushCachedDeserializers() { } /** - * Method used to provide cache instance for {@link DefaultCacheProvider#defaultInstance()}. + * Method used to provide cache instance for + * {@link DefaultCacheProvider#defaultInstance()}. * * @since 2.16 */ public static LookupCache> defaultCache() { - return new LRUMap<>(Math.min(64, MAX_CACHE_SIZE >>2), MAX_CACHE_SIZE); + return _createCache(MAX_CACHE_SIZE); } /* From e1132d6a2d73960f0568eb02195429776de72eef Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:27:48 +0900 Subject: [PATCH 31/53] Improve JavaDoc --- .../databind/cfg/DefaultCacheProvider.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index d738ae312c..78fce0de0e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -40,6 +40,9 @@ protected DefaultCacheProvider(LookupCache> d /********************************************************************** */ + /** + * @return Default {@link DefaultCacheProvider} instance for default configuration and null-safety. + */ public static CacheProvider defaultInstance() { return new DefaultCacheProvider(DeserializerCache.defaultCache()); } @@ -61,6 +64,9 @@ public LookupCache> provideForDeserializerCac /********************************************************** */ + /** + * @return Builder instance to construct {@link DefaultCacheProvider} instance. + */ public static DefaultCacheProvider.Builder builder() { return new Builder(); } @@ -70,18 +76,25 @@ public static DefaultCacheProvider.Builder builder() { * and to keep {@link DefaultCacheProvider} immutable. */ public static class Builder { - + + /** + * Counter part of {@link DefaultCacheProvider#_deserializerCache}. + */ private LookupCache> _deserializerCache; protected Builder() { } - public DefaultCacheProvider build() { - return new DefaultCacheProvider(_deserializerCache); - } - public Builder deserializerCache(LookupCache> deserializerCache) { _deserializerCache = deserializerCache; return this; } + + /** + * @return Constructs and returns a {@link DefaultCacheProvider} instance with given configuration. + */ + public DefaultCacheProvider build() { + return new DefaultCacheProvider(_deserializerCache); + } + } } From e369d0c2df70839947b81d49261f54c6278ccf4a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:34:48 +0900 Subject: [PATCH 32/53] Improve Doc and method order --- .../databind/deser/DeserializerCache.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 9157488361..d967132cd4 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -75,15 +75,6 @@ public DeserializerCache(LookupCache> cache) _cachedDeserializers = cache; } - /** - * Internal method to create actual cache instance for {@link #_cachedDeserializers} - * - * @since 2.16 - */ - private static LookupCache> _createCache(int maxSize) { - return new LRUMap<>(Math.min(64, maxSize>>2), maxSize); - } - /* /********************************************************** /* JDK serialization handling @@ -130,8 +121,8 @@ public void flushCachedDeserializers() { } /** - * Method used to provide cache instance for - * {@link DefaultCacheProvider#defaultInstance()}. + * Constructs and returns {@link LookupCache} instance using + * default settings used to construct {@link #_cachedDeserializers}. * * @since 2.16 */ @@ -139,6 +130,15 @@ public static LookupCache> defaultCache() { return _createCache(MAX_CACHE_SIZE); } + /** + * Internal method to create actual cache instance for {@link #_cachedDeserializers} + * + * @since 2.16 + */ + private static LookupCache> _createCache(int maxSize) { + return new LRUMap<>(Math.min(64, maxSize>>2), maxSize); + } + /* /********************************************************** /* General deserializer locating method From 95b6a2f5c31402dd59db10dc253c98dd99dff1dc Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:52:11 +0900 Subject: [PATCH 33/53] Apply review --- .../java/com/fasterxml/jackson/databind/cfg/CacheProvider.java | 3 ++- .../fasterxml/jackson/databind/cfg/DefaultCacheProvider.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java index 78b697f331..67095c208d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java @@ -1,5 +1,6 @@ package com.fasterxml.jackson.databind.cfg; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.DeserializerCache; @@ -21,6 +22,6 @@ public interface CacheProvider * * @return {@link LookupCache} instance for caching {@link JsonDeserializer}s */ - LookupCache> provideForDeserializerCache(); + LookupCache> forDeserializerCache(DeserializationConfig config); } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 78fce0de0e..60872635c9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -54,7 +54,7 @@ public static CacheProvider defaultInstance() { */ @Override - public LookupCache> provideForDeserializerCache() { + public LookupCache> forDeserializerCache() { return _deserializerCache; } From 6350496168eff9de29b37a3b13c4d10ee18645af Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:52:37 +0900 Subject: [PATCH 34/53] Update SerializationConfig.java --- .../com/fasterxml/jackson/databind/SerializationConfig.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java b/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java index 3bdc008f7d..a710d51ab8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/SerializationConfig.java @@ -299,11 +299,6 @@ protected SerializationConfig(SerializationConfig src, DatatypeFeatures dtFeatur _formatWriteFeaturesToChange = src._formatWriteFeaturesToChange; } - /** - * @since 2.16 - */ - protected BaseSettings getBaseSettings() { return _base; } - /* /********************************************************** /* Life-cycle, factory methods from MapperConfig(Base) From 6a7ec46b5de95161f4ed5b6132a3e411e3db794a Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:55:00 +0900 Subject: [PATCH 35/53] Remove accessor conflict --- .../com/fasterxml/jackson/databind/cfg/MapperConfig.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java index 36b09ca830..5e97bcd9d6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java @@ -691,13 +691,6 @@ public Base64Variant getBase64Variant() { */ public abstract PropertyName findRootName(Class rawRootType); - /** - * @since 2.16 - */ - public CacheProvider getCacheProvider() { - return _base.getCacheProvider(); - } - /* /********************************************************** /* Methods for instantiating handlers From 701d1a56db1514275215df1546dd12de674c5f00 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 12:55:52 +0900 Subject: [PATCH 36/53] Update DefaultCacheProvider.java --- .../fasterxml/jackson/databind/cfg/DefaultCacheProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 60872635c9..e2b7f05925 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -1,5 +1,6 @@ package com.fasterxml.jackson.databind.cfg; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.DeserializerCache; @@ -54,7 +55,7 @@ public static CacheProvider defaultInstance() { */ @Override - public LookupCache> forDeserializerCache() { + public LookupCache> forDeserializerCache(DeserializationConfig config) { return _deserializerCache; } From aff462e239d036e2d27e58b5a98a1e0094ba8912 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 13:02:51 +0900 Subject: [PATCH 37/53] Minimize more changes. --- .../jackson/databind/cfg/MapperConfig.java | 14 +++++++------- .../jackson/databind/cfg/MapperConfigBase.java | 7 +------ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java index 5e97bcd9d6..d31f39cf9b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfig.java @@ -674,13 +674,6 @@ public Base64Variant getBase64Variant() { */ public abstract ContextAttributes getAttributes(); - /** - * Method for accessing configured {@link CacheProvider} via {@link MapperBuilder#cacheProvider(CacheProvider)}. - * - * @since 2.16 - */ - public abstract CacheProvider getCacheProvider(); - /** * @since 2.6 */ @@ -691,6 +684,13 @@ public Base64Variant getBase64Variant() { */ public abstract PropertyName findRootName(Class rawRootType); + /** + * @since 2.16 + */ + public CacheProvider getCacheProvider() { + return _base.getCacheProvider(); + } + /* /********************************************************** /* Methods for instantiating handlers diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java index 48deba3de3..9d2f1751a2 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperConfigBase.java @@ -881,7 +881,7 @@ public Boolean getDefaultMergeable(Class baseType) { } return _configOverrides.getDefaultMergeable(); } - + /* /********************************************************************** /* Other config access @@ -904,11 +904,6 @@ public PropertyName findRootName(Class rawRootType) { return _rootNames.findRootName(rawRootType, this); } - @Override // Since 2.16 - public CacheProvider getCacheProvider() { - return _base.getCacheProvider(); - } - /* /********************************************************************** /* ClassIntrospector.MixInResolver impl: From 91875338964376ff1b97e6c4b07320cb1bf40b58 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 20:58:54 +0900 Subject: [PATCH 38/53] Solution 2 : Configure CacheProvider when setting CacheProvider --- .../databind/DeserializationContext.java | 14 +++ .../jackson/databind/ObjectMapper.java | 1 + .../jackson/databind/cfg/CacheProvider.java | 9 +- .../databind/cfg/DefaultCacheProvider.java | 20 +++- .../deser/DefaultDeserializationContext.java | 26 +++++ .../databind/cfg/CacheProviderTest.java | 102 +++++++++++++++--- 6 files changed, 144 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 8cecc2be70..15fdf40200 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -199,6 +199,20 @@ protected DeserializationContext(DeserializationContext src, _attributes = src._attributes; } + protected DeserializationContext(DeserializationContext src, + DeserializerCache cache) + { + _cache = cache; + _factory = src._factory; + + _config = src._config; + _featureFlags = src._featureFlags; + _readCapabilities = src._readCapabilities; + _view = src._view; + _parser = src._parser; + _injectableValues = src._injectableValues; + _attributes = src._attributes; + } /** * Constructor used for creating actual per-call instances. */ diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 2c6823501d..7dd037667c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2277,6 +2277,7 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { _deserializationConfig = _deserializationConfig.with(cacheProvider); _serializationConfig = _serializationConfig.with(cacheProvider); + _deserializationContext = _deserializationContext.with(cacheProvider.forDeserializerCache(_deserializationConfig)); return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java index 67095c208d..73bd286c1d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java @@ -1,10 +1,7 @@ package com.fasterxml.jackson.databind.cfg; import com.fasterxml.jackson.databind.DeserializationConfig; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.DeserializerCache; -import com.fasterxml.jackson.databind.util.LookupCache; /** * Interface that defines API Jackson uses for constructing various internal @@ -18,10 +15,8 @@ public interface CacheProvider extends java.io.Serializable { /** - * Method to provide a {@link LookupCache} instance for {@link DeserializerCache} - * - * @return {@link LookupCache} instance for caching {@link JsonDeserializer}s + * Method to provide a {@link DeserializerCache} instance. */ - LookupCache> forDeserializerCache(DeserializationConfig config); + DeserializerCache forDeserializerCache(DeserializationConfig config); } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index e2b7f05925..28b0a89c5b 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -9,8 +9,11 @@ /** * Default implementation of {@link CacheProvider}. * Provides builder-based custom cache configuration using {@link DefaultCacheProvider.Builder}. - *

* Users can either use {@link DefaultCacheProvider.Builder} or write their own {@link CacheProvider} imlementation. + *

+ * WARNING: Configured cache instances using {@link DefaultCacheProvider.Builder} are "shared". + * Meaning that if you use same {@link DefaultCacheProvider} instance to construct multiple + * {@link com.fasterxml.jackson.databind.ObjectMapper} instances, they will share the same cache instances. * * @since 2.16 */ @@ -20,7 +23,7 @@ public class DefaultCacheProvider private static final long serialVersionUID = 1L; /** - * Cache instance to provide for {@link DeserializerCache}. + * {@link LookupCache} instance to be used create {@link DeserializerCache} instance when {@link #forDeserializerCache} is invoked. */ protected final LookupCache> _deserializerCache; @@ -55,8 +58,8 @@ public static CacheProvider defaultInstance() { */ @Override - public LookupCache> forDeserializerCache(DeserializationConfig config) { - return _deserializerCache; + public DeserializerCache forDeserializerCache(DeserializationConfig config) { + return new DeserializerCache(_deserializerCache); } /* @@ -85,7 +88,16 @@ public static class Builder { protected Builder() { } + /** + * Fluent API for configuring {@link DefaultCacheProvider#_deserializerCache} instance for {@link DefaultCacheProvider}. + * + * @param deserializerCache {@link LookupCache} instance to be used create {@link DeserializerCache} instance. + * @throws IllegalArgumentException if {@code deserializerCache} is null. + */ public Builder deserializerCache(LookupCache> deserializerCache) { + if (deserializerCache == null) { + throw new IllegalArgumentException("Cannot pass null deserializerCache"); + } _deserializerCache = deserializerCache; return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 0e57e3ccb0..e1fd45d519 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -61,6 +61,14 @@ protected DefaultDeserializationContext(DefaultDeserializationContext src, super(src, factory); } + /** + * @since 2.16 + */ + protected DefaultDeserializationContext(DefaultDeserializationContext src, + DeserializerCache cache) { + super(src, cache); + } + /** * @since 2.4.4 */ @@ -296,6 +304,12 @@ public final KeyDeserializer keyDeserializerInstance(Annotated ann, Object deser */ public abstract DefaultDeserializationContext with(DeserializerFactory factory); + /** + * Fluent factory method used for constructing a new instance with configured {@link DeserializerCache}. + * @since 2.16 + */ + public abstract DefaultDeserializationContext with(DeserializerCache deserializerCache); + /** * Method called to create actual usable per-deserialization * context instance. @@ -402,6 +416,13 @@ private Impl(Impl src, DeserializationConfig config) { super(src, config); } + /** + * @since 2.16 + */ + private Impl(Impl src, DeserializerCache deserializerCache) { + super(src, deserializerCache); + } + @Override public DefaultDeserializationContext copy() { ClassUtil.verifyMustOverride(Impl.class, this, "copy"); @@ -424,5 +445,10 @@ public DefaultDeserializationContext createDummyInstance(DeserializationConfig c public DefaultDeserializationContext with(DeserializerFactory factory) { return new Impl(this, factory); } + + @Override // Since 2.16 + public DefaultDeserializationContext with(DeserializerCache deserializerCache) { + return new Impl(this, deserializerCache); + } } } diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 181a158902..ca6c4fbf6e 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -1,16 +1,19 @@ package com.fasterxml.jackson.databind.cfg; -import java.util.HashMap; - import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.util.LookupCache; +import org.junit.Before; import org.junit.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; /** * @@ -18,58 +21,123 @@ * * @since 2.16 */ -public class CacheProviderTest { - +public class CacheProviderTest +{ + static class RandomBean { public int point; } + static class AnotherBean { + public int height; + } + static class SimpleTestCache implements LookupCache> { - final HashMap> cache = new HashMap<>(); + final HashMap> _cachedDeserializers; + + public SimpleTestCache(int cacheSize) { + _cachedDeserializers = new HashMap<>(cacheSize); + createdCaches.add(_cachedDeserializers); + } @Override public int size() { - return cache.size(); + return _cachedDeserializers.size(); } @Override public JsonDeserializer get(Object key) { invoked = true; - return cache.get(key); + return _cachedDeserializers.get(key); } @Override public JsonDeserializer put(JavaType key, JsonDeserializer value) { invoked = true; - return cache.put(key, value); + return _cachedDeserializers.put(key, value); } @Override public JsonDeserializer putIfAbsent(JavaType key, JsonDeserializer value) { invoked = true; - return cache.putIfAbsent(key, value); + return _cachedDeserializers.putIfAbsent(key, value); } @Override public void clear() { - cache.clear(); + _cachedDeserializers.clear(); } } - // Checking the cache was actually used + @Before + public void setUp() { + createdCaches.clear(); + invoked = false; + } + + // For checking the cache was actually used private static boolean invoked = false; + // For checking the cache was actually created + private static final List>> createdCaches = new ArrayList<>(); + @Test - public void testCacheConfig() throws Exception { + public void testCacheConfig() throws Exception + { DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .deserializerCache(new SimpleTestCache()) + .deserializerCache(new SimpleTestCache(1234)) .build(); + ObjectMapper mapper = JsonMapper.builder() .cacheProvider(cacheProvider).build(); - RandomBean bean = mapper.readValue("{\"point\":24}", RandomBean.class); - assertEquals(24, bean.point); + mapper.readValue("{\"point\":24}", RandomBean.class); + assertTrue(invoked); } + + @Test + public void testNullCheckingForDeserializerCacheConfig() throws Exception + { + try { + DefaultCacheProvider.builder() + .deserializerCache(null); + fail("Should not reach here"); + } catch (IllegalArgumentException e) { + assertEquals("Cannot pass null deserializerCache", e.getMessage()); + } + } + + @Test + public void testDefaultCacheProviderSharesCache() throws Exception + { + // Arrange + // 1. shared CacheProvider + DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() + .deserializerCache(new SimpleTestCache(1234)) + .build(); + + // 2. two different mapper instances + ObjectMapper mapper1 = JsonMapper.builder() + .cacheProvider(cacheProvider) + .build(); + ObjectMapper mapper2 = JsonMapper.builder() + .cacheProvider(cacheProvider) + .build(); + + // Act + // 3. Add two different types to each mapper cache + mapper1.readValue("{\"point\":24}", RandomBean.class); + mapper2.readValue("{\"height\":24}", AnotherBean.class); + + // Assert + // 4. Should have created only one cache instance, shared between mappers + assertEquals(1, createdCaches.size()); + Map> cache = createdCaches.get(0); + + // 5. Should not share cache entries + JavaType type1 = mapper1.getTypeFactory().constructType(RandomBean.class); + JavaType type2 = mapper1.getTypeFactory().constructType(AnotherBean.class); + } } From 68716c814c498ef9597b87837903ccf0cb8505a8 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 21:23:49 +0900 Subject: [PATCH 39/53] Improve test and doc around DefaultCacheProvider.Builder --- .../databind/DeserializationContext.java | 3 ++ .../databind/cfg/DefaultCacheProvider.java | 10 +++++- .../databind/cfg/CacheProviderTest.java | 35 ++++++++++++------- 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 15fdf40200..4c50e39b68 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -199,6 +199,9 @@ protected DeserializationContext(DeserializationContext src, _attributes = src._attributes; } + /** + * @since 2.16 + */ protected DeserializationContext(DeserializationContext src, DeserializerCache cache) { diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 28b0a89c5b..611e5e7a9c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.databind.deser.DeserializerCache; import com.fasterxml.jackson.databind.util.LookupCache; +import java.util.Objects; + /** * Default implementation of {@link CacheProvider}. * Provides builder-based custom cache configuration using {@link DefaultCacheProvider.Builder}. @@ -103,10 +105,16 @@ public Builder deserializerCache(LookupCache> } /** + * Constructs and returns a {@link DefaultCacheProvider} instance with given configuration. + * If any of the configuration is not set, it will use default configuration. + * * @return Constructs and returns a {@link DefaultCacheProvider} instance with given configuration. */ public DefaultCacheProvider build() { - return new DefaultCacheProvider(_deserializerCache); + LookupCache> deserializerCache = Objects.isNull(_deserializerCache) + ? DeserializerCache.defaultCache() : _deserializerCache; + + return new DefaultCacheProvider(deserializerCache); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index ca6c4fbf6e..3434653d5e 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -96,18 +96,6 @@ public void testCacheConfig() throws Exception assertTrue(invoked); } - - @Test - public void testNullCheckingForDeserializerCacheConfig() throws Exception - { - try { - DefaultCacheProvider.builder() - .deserializerCache(null); - fail("Should not reach here"); - } catch (IllegalArgumentException e) { - assertEquals("Cannot pass null deserializerCache", e.getMessage()); - } - } @Test public void testDefaultCacheProviderSharesCache() throws Exception @@ -140,4 +128,27 @@ public void testDefaultCacheProviderSharesCache() throws Exception JavaType type1 = mapper1.getTypeFactory().constructType(RandomBean.class); JavaType type2 = mapper1.getTypeFactory().constructType(AnotherBean.class); } + + + @Test + public void testBuilderNullCheckingForDeserializerCacheConfig() throws Exception + { + try { + DefaultCacheProvider.builder() + .deserializerCache(null); + fail("Should not reach here"); + } catch (IllegalArgumentException e) { + assertEquals("Cannot pass null deserializerCache", e.getMessage()); + } + } + + @Test + public void testBuilderBuildWithDefaults() throws Exception + { + try { + DefaultCacheProvider.builder().build(); + } catch (IllegalArgumentException e) { + fail("Should not reach here"); + } + } } From b44a8bcba295e5033d623cf8c9f512f809740d95 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sat, 2 Sep 2023 23:41:28 +0900 Subject: [PATCH 40/53] Clean up JavaDoc and add a test --- .../databind/DeserializationContext.java | 1 + .../databind/cfg/DefaultCacheProvider.java | 16 ++++---- .../deser/DefaultDeserializationContext.java | 2 +- .../databind/deser/DeserializerCache.java | 3 +- .../databind/cfg/CacheProviderTest.java | 40 +++++++++++++++---- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 4c50e39b68..19237be32c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -216,6 +216,7 @@ protected DeserializationContext(DeserializationContext src, _injectableValues = src._injectableValues; _attributes = src._attributes; } + /** * Constructor used for creating actual per-call instances. */ diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 611e5e7a9c..48a2b8a56c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -11,9 +11,9 @@ /** * Default implementation of {@link CacheProvider}. * Provides builder-based custom cache configuration using {@link DefaultCacheProvider.Builder}. - * Users can either use {@link DefaultCacheProvider.Builder} or write their own {@link CacheProvider} imlementation. + * Users can either use this class or implement their own {@link CacheProvider} imlementation. *

- * WARNING: Configured cache instances using {@link DefaultCacheProvider.Builder} are "shared". + * WARNING: Configured cache instances are
shared. * Meaning that if you use same {@link DefaultCacheProvider} instance to construct multiple * {@link com.fasterxml.jackson.databind.ObjectMapper} instances, they will share the same cache instances. * @@ -25,7 +25,7 @@ public class DefaultCacheProvider private static final long serialVersionUID = 1L; /** - * {@link LookupCache} instance to be used create {@link DeserializerCache} instance when {@link #forDeserializerCache} is invoked. + * {@link LookupCache} instance used to create {@link DeserializerCache} instance when {@link #forDeserializerCache} is invoked. */ protected final LookupCache> _deserializerCache; @@ -47,7 +47,7 @@ protected DefaultCacheProvider(LookupCache> d */ /** - * @return Default {@link DefaultCacheProvider} instance for default configuration and null-safety. + * @return Default {@link DefaultCacheProvider} instance with default configuration values. */ public static CacheProvider defaultInstance() { return new DefaultCacheProvider(DeserializerCache.defaultCache()); @@ -84,11 +84,13 @@ public static DefaultCacheProvider.Builder builder() { public static class Builder { /** + * {@link LookupCache} instance used to create {@link DeserializerCache} instance when {@link #forDeserializerCache} is invoked. + * * Counter part of {@link DefaultCacheProvider#_deserializerCache}. */ private LookupCache> _deserializerCache; - protected Builder() { } + private Builder() { } /** * Fluent API for configuring {@link DefaultCacheProvider#_deserializerCache} instance for {@link DefaultCacheProvider}. @@ -111,8 +113,8 @@ public Builder deserializerCache(LookupCache> * @return Constructs and returns a {@link DefaultCacheProvider} instance with given configuration. */ public DefaultCacheProvider build() { - LookupCache> deserializerCache = Objects.isNull(_deserializerCache) - ? DeserializerCache.defaultCache() : _deserializerCache; + LookupCache> deserializerCache = + Objects.isNull(_deserializerCache) ? DeserializerCache.defaultCache() : _deserializerCache; return new DefaultCacheProvider(deserializerCache); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index e1fd45d519..f0e14979af 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -65,7 +65,7 @@ protected DefaultDeserializationContext(DefaultDeserializationContext src, * @since 2.16 */ protected DefaultDeserializationContext(DefaultDeserializationContext src, - DeserializerCache cache) { + DeserializerCache cache) { super(src, cache); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index d967132cd4..f361d04d5e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -121,8 +121,7 @@ public void flushCachedDeserializers() { } /** - * Constructs and returns {@link LookupCache} instance using - * default settings used to construct {@link #_cachedDeserializers}. + * Constructs and returns {@link LookupCache} instance with default settings. * * @since 2.16 */ diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 3434653d5e..40b45a8a8d 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -1,8 +1,10 @@ package com.fasterxml.jackson.databind.cfg; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.DeserializerCache; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.util.LookupCache; import org.junit.Before; @@ -69,26 +71,38 @@ public void clear() { _cachedDeserializers.clear(); } } - - @Before - public void setUp() { - createdCaches.clear(); - invoked = false; + + static class CustomCacheProvider implements CacheProvider { + @Override + public DeserializerCache forDeserializerCache(DeserializationConfig config) { + return new DeserializerCache(DeserializerCache.defaultCache()); + } } + + /* + /********************************************************************** + /* Unit tests + /********************************************************************** + */ // For checking the cache was actually used private static boolean invoked = false; // For checking the cache was actually created private static final List>> createdCaches = new ArrayList<>(); + + @Before + public void setUp() { + createdCaches.clear(); + invoked = false; + } @Test - public void testCacheConfig() throws Exception + public void testDefaultCacheProviderConfig() throws Exception { DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() .deserializerCache(new SimpleTestCache(1234)) .build(); - ObjectMapper mapper = JsonMapper.builder() .cacheProvider(cacheProvider).build(); @@ -97,6 +111,16 @@ public void testCacheConfig() throws Exception assertTrue(invoked); } + @Test + public void testCustomCacheProviderConfig() throws Exception + { + ObjectMapper mapper = JsonMapper.builder() + .cacheProvider(new CustomCacheProvider()) + .build(); + + assertNotNull(mapper.readValue("{\"point\":24}", RandomBean.class)); + } + @Test public void testDefaultCacheProviderSharesCache() throws Exception { @@ -151,4 +175,6 @@ public void testBuilderBuildWithDefaults() throws Exception fail("Should not reach here"); } } + + } From 70b4558144a09a139ad6870109d596f725e5cbb5 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 3 Sep 2023 10:10:35 +0900 Subject: [PATCH 41/53] Apply review on DefaultCacheProvider and CacheProvider --- .../jackson/databind/cfg/CacheProvider.java | 11 +++-- .../databind/cfg/DefaultCacheProvider.java | 48 +++++++++---------- .../databind/deser/DeserializerCache.java | 7 ++- .../databind/cfg/CacheProviderTest.java | 8 ++-- 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java index 73bd286c1d..a134c857e1 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java @@ -1,13 +1,16 @@ package com.fasterxml.jackson.databind.cfg; import com.fasterxml.jackson.databind.DeserializationConfig; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.DeserializerCache; +import com.fasterxml.jackson.databind.util.LookupCache; /** * Interface that defines API Jackson uses for constructing various internal * caches. This allows configuring custom caches and cache configurations. * A {@link CacheProvider} instance will be configured through a builder such as - * {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)} + * {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)}. * * @since 2.16 */ @@ -15,8 +18,10 @@ public interface CacheProvider extends java.io.Serializable { /** - * Method to provide a {@link DeserializerCache} instance. + * Method to provide a {@link LookupCache} instance for constructing {@link DeserializerCache}. + * + * @return {@link LookupCache} instance for constructing {@link DeserializerCache}. */ - DeserializerCache forDeserializerCache(DeserializationConfig config); + LookupCache> forDeserializerCache(DeserializationConfig config); } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 48a2b8a56c..58264c3f79 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.DeserializerCache; +import com.fasterxml.jackson.databind.util.LRUMap; import com.fasterxml.jackson.databind.util.LookupCache; import java.util.Objects; @@ -25,9 +26,10 @@ public class DefaultCacheProvider private static final long serialVersionUID = 1L; /** - * {@link LookupCache} instance used to create {@link DeserializerCache} instance when {@link #forDeserializerCache} is invoked. + * Size of {@link LookupCache} instance to create when {@link #forDeserializerCache(DeserializationConfig)} + * is invoked. */ - protected final LookupCache> _deserializerCache; + protected final int _deserializerCacheSize; /* /********************************************************************** @@ -35,9 +37,9 @@ public class DefaultCacheProvider /********************************************************************** */ - protected DefaultCacheProvider(LookupCache> deserializerCache) + protected DefaultCacheProvider(int deserializerCache) { - _deserializerCache = deserializerCache; + _deserializerCacheSize = deserializerCache; } /* @@ -50,7 +52,7 @@ protected DefaultCacheProvider(LookupCache> d * @return Default {@link DefaultCacheProvider} instance with default configuration values. */ public static CacheProvider defaultInstance() { - return new DefaultCacheProvider(DeserializerCache.defaultCache()); + return new DefaultCacheProvider(DeserializerCache.DEFAULT_MAX_CACHE_SIZE); } /* @@ -60,8 +62,8 @@ public static CacheProvider defaultInstance() { */ @Override - public DeserializerCache forDeserializerCache(DeserializationConfig config) { - return new DeserializerCache(_deserializerCache); + public LookupCache> forDeserializerCache(DeserializationConfig config) { + return new LRUMap<>(Math.min(64, _deserializerCacheSize >> 2), _deserializerCacheSize); } /* @@ -84,25 +86,26 @@ public static DefaultCacheProvider.Builder builder() { public static class Builder { /** - * {@link LookupCache} instance used to create {@link DeserializerCache} instance when {@link #forDeserializerCache} is invoked. - * - * Counter part of {@link DefaultCacheProvider#_deserializerCache}. + * Size of {@link LookupCache} instance to create when {@link #forDeserializerCache(DeserializationConfig)} + * is invoked. + * Counter part of {@link DefaultCacheProvider#_deserializerCacheSize}. */ - private LookupCache> _deserializerCache; + private int _deserializerCacheSize; private Builder() { } /** - * Fluent API for configuring {@link DefaultCacheProvider#_deserializerCache} instance for {@link DefaultCacheProvider}. - * - * @param deserializerCache {@link LookupCache} instance to be used create {@link DeserializerCache} instance. - * @throws IllegalArgumentException if {@code deserializerCache} is null. + * @param deserializerCacheSize Size of {@link LookupCache} instance to create when + * {@link #forDeserializerCache(DeserializationConfig)} is invoked + * @return this builder + * @throws IllegalArgumentException if the {@code deserializerCacheSize} is negative value + * @since 2.16 */ - public Builder deserializerCache(LookupCache> deserializerCache) { - if (deserializerCache == null) { - throw new IllegalArgumentException("Cannot pass null deserializerCache"); + public Builder deserializerCacheSize(int deserializerCacheSize) { + if (deserializerCacheSize < 0) { + throw new IllegalArgumentException("Cannot pass negative value for deserializerCacheSize."); } - _deserializerCache = deserializerCache; + _deserializerCacheSize = deserializerCacheSize; return this; } @@ -110,13 +113,10 @@ public Builder deserializerCache(LookupCache> * Constructs and returns a {@link DefaultCacheProvider} instance with given configuration. * If any of the configuration is not set, it will use default configuration. * - * @return Constructs and returns a {@link DefaultCacheProvider} instance with given configuration. + * @return Constructs and returns a {@link DefaultCacheProvider} instance with given configuration */ public DefaultCacheProvider build() { - LookupCache> deserializerCache = - Objects.isNull(_deserializerCache) ? DeserializerCache.defaultCache() : _deserializerCache; - - return new DefaultCacheProvider(deserializerCache); + return new DefaultCacheProvider(_deserializerCacheSize); } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index f361d04d5e..901b8409ab 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.cfg.DefaultCacheProvider; import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.type.*; @@ -31,7 +30,7 @@ public final class DeserializerCache * * @since 2.16 */ - private final static int MAX_CACHE_SIZE = 2000; + public final static int DEFAULT_MAX_CACHE_SIZE = 2000; /* /********************************************************** @@ -61,7 +60,7 @@ public final class DeserializerCache */ public DeserializerCache() { - this(MAX_CACHE_SIZE); // see [databind#1995] + this(DEFAULT_MAX_CACHE_SIZE); // see [databind#1995] } public DeserializerCache(int maxSize) { @@ -126,7 +125,7 @@ public void flushCachedDeserializers() { * @since 2.16 */ public static LookupCache> defaultCache() { - return _createCache(MAX_CACHE_SIZE); + return _createCache(DEFAULT_MAX_CACHE_SIZE); } /** diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 40b45a8a8d..a8ff4a4225 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -101,7 +101,7 @@ public void setUp() { public void testDefaultCacheProviderConfig() throws Exception { DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .deserializerCache(new SimpleTestCache(1234)) + .deserializerCacheSize(new SimpleTestCache(1234)) .build(); ObjectMapper mapper = JsonMapper.builder() .cacheProvider(cacheProvider).build(); @@ -127,7 +127,7 @@ public void testDefaultCacheProviderSharesCache() throws Exception // Arrange // 1. shared CacheProvider DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .deserializerCache(new SimpleTestCache(1234)) + .deserializerCacheSize(new SimpleTestCache(1234)) .build(); // 2. two different mapper instances @@ -159,10 +159,10 @@ public void testBuilderNullCheckingForDeserializerCacheConfig() throws Exception { try { DefaultCacheProvider.builder() - .deserializerCache(null); + .deserializerCacheSize(null); fail("Should not reach here"); } catch (IllegalArgumentException e) { - assertEquals("Cannot pass null deserializerCache", e.getMessage()); + assertEquals("Cannot pass null deserializerCacheSize", e.getMessage()); } } From 7f471324aab9476fb506392ad8c4e8d6dfb8822c Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 3 Sep 2023 10:40:07 +0900 Subject: [PATCH 42/53] Implement withCaches --- .../jackson/databind/ObjectMapper.java | 4 ++- .../databind/cfg/DefaultCacheProvider.java | 12 +++++-- .../deser/DefaultDeserializationContext.java | 10 ++++-- .../databind/cfg/CacheProviderTest.java | 35 +++++++------------ 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 7dd037667c..8845d4c8a8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2272,12 +2272,14 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) { /** * Method for specifying {@link CacheProvider} instance, to provide Cache instances to be used in components downstream. * + * @throws IllegalArgumentException if given provider is null * @since 2.16 */ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) { + _assertNotNull("cacheProvider", cacheProvider); _deserializationConfig = _deserializationConfig.with(cacheProvider); _serializationConfig = _serializationConfig.with(cacheProvider); - _deserializationContext = _deserializationContext.with(cacheProvider.forDeserializerCache(_deserializationConfig)); + _deserializationContext = _deserializationContext.withCaches(cacheProvider); return this; } diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 58264c3f79..2669c6e683 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -95,15 +95,21 @@ public static class Builder { private Builder() { } /** - * @param deserializerCacheSize Size of {@link LookupCache} instance to create when - * {@link #forDeserializerCache(DeserializationConfig)} is invoked + * Configures the size of {@link LookupCache} instance to create when {@link #forDeserializerCache(DeserializationConfig)} is invoked. + * Currently, the cache instance is constructed as + *

+         *     new LRUMap<>(Math.min(64, size >> 2), size)
+         * 
+ * ...such in {@link #forDeserializerCache(DeserializationConfig)} + * + * @param deserializerCacheSize Size of {@link LookupCache} instance to construct for {@link DeserializerCache} * @return this builder * @throws IllegalArgumentException if the {@code deserializerCacheSize} is negative value * @since 2.16 */ public Builder deserializerCacheSize(int deserializerCacheSize) { if (deserializerCacheSize < 0) { - throw new IllegalArgumentException("Cannot pass negative value for deserializerCacheSize."); + throw new IllegalArgumentException("Cannot set deserializerCacheSize to a negative value"); } _deserializerCacheSize = deserializerCacheSize; return this; diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index f0e14979af..418b52dd59 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.cfg.CacheProvider; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId; import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring; @@ -305,10 +306,11 @@ public final KeyDeserializer keyDeserializerInstance(Annotated ann, Object deser public abstract DefaultDeserializationContext with(DeserializerFactory factory); /** - * Fluent factory method used for constructing a new instance with configured {@link DeserializerCache}. + * Fluent factory method used for constructing a new instance with cache instances provided by {@link CacheProvider}. + * * @since 2.16 */ - public abstract DefaultDeserializationContext with(DeserializerCache deserializerCache); + public abstract DefaultDeserializationContext withCaches(CacheProvider cacheProvider); /** * Method called to create actual usable per-deserialization @@ -447,7 +449,9 @@ public DefaultDeserializationContext with(DeserializerFactory factory) { } @Override // Since 2.16 - public DefaultDeserializationContext with(DeserializerCache deserializerCache) { + public DefaultDeserializationContext withCaches(CacheProvider cacheProvider) { + DeserializerCache deserializerCache = new DeserializerCache(cacheProvider.forDeserializerCache(_config)); + return new Impl(this, deserializerCache); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index a8ff4a4225..474a4da991 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -74,8 +74,9 @@ public void clear() { static class CustomCacheProvider implements CacheProvider { @Override - public DeserializerCache forDeserializerCache(DeserializationConfig config) { - return new DeserializerCache(DeserializerCache.defaultCache()); + public LookupCache> forDeserializerCache(DeserializationConfig config) { + invoked = true; + return new SimpleTestCache(123); } } @@ -85,7 +86,7 @@ public DeserializerCache forDeserializerCache(DeserializationConfig config) { /********************************************************************** */ - // For checking the cache was actually used + // For checking CustomCacheProvider.forDeserializerCache() was actually used private static boolean invoked = false; // For checking the cache was actually created @@ -100,15 +101,13 @@ public void setUp() { @Test public void testDefaultCacheProviderConfig() throws Exception { - DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .deserializerCacheSize(new SimpleTestCache(1234)) + CacheProvider cacheProvider = DefaultCacheProvider.builder() + .deserializerCacheSize(1234) .build(); ObjectMapper mapper = JsonMapper.builder() .cacheProvider(cacheProvider).build(); - mapper.readValue("{\"point\":24}", RandomBean.class); - - assertTrue(invoked); + assertNotNull(mapper.readValue("{\"point\":24}", RandomBean.class)); } @Test @@ -118,6 +117,7 @@ public void testCustomCacheProviderConfig() throws Exception .cacheProvider(new CustomCacheProvider()) .build(); + assertTrue(invoked); assertNotNull(mapper.readValue("{\"point\":24}", RandomBean.class)); } @@ -126,9 +126,7 @@ public void testDefaultCacheProviderSharesCache() throws Exception { // Arrange // 1. shared CacheProvider - DefaultCacheProvider cacheProvider = DefaultCacheProvider.builder() - .deserializerCacheSize(new SimpleTestCache(1234)) - .build(); + CacheProvider cacheProvider = new CustomCacheProvider(); // 2. two different mapper instances ObjectMapper mapper1 = JsonMapper.builder() @@ -144,13 +142,8 @@ public void testDefaultCacheProviderSharesCache() throws Exception mapper2.readValue("{\"height\":24}", AnotherBean.class); // Assert - // 4. Should have created only one cache instance, shared between mappers - assertEquals(1, createdCaches.size()); - Map> cache = createdCaches.get(0); - - // 5. Should not share cache entries - JavaType type1 = mapper1.getTypeFactory().constructType(RandomBean.class); - JavaType type2 = mapper1.getTypeFactory().constructType(AnotherBean.class); + // 4. Should have created two cache instance + assertEquals(2, createdCaches.size()); } @@ -159,10 +152,10 @@ public void testBuilderNullCheckingForDeserializerCacheConfig() throws Exception { try { DefaultCacheProvider.builder() - .deserializerCacheSize(null); + .deserializerCacheSize(-1); fail("Should not reach here"); } catch (IllegalArgumentException e) { - assertEquals("Cannot pass null deserializerCacheSize", e.getMessage()); + assertTrue(e.getMessage().contains("Cannot set deserializerCacheSize to a negative value")); } } @@ -175,6 +168,4 @@ public void testBuilderBuildWithDefaults() throws Exception fail("Should not reach here"); } } - - } From 3749efd1dacddf59bd8cc41df93dddde07cb5cf4 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 3 Sep 2023 17:38:56 +0900 Subject: [PATCH 43/53] Revert DeserializerCache changes, except DEFAULT_MAX_CACHE_SIZE constant --- .../databind/deser/DeserializerCache.java | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 901b8409ab..e697974506 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -25,7 +25,7 @@ public final class DeserializerCache private static final long serialVersionUID = 1L; /** - * Previously was passed inline in {@link #DeserializerCache(int)}. + * Previously was passed to {@link DeserializerCache} constructors "inline". * Declared as field since 2.16. * * @since 2.16 @@ -64,7 +64,7 @@ public DeserializerCache() { } public DeserializerCache(int maxSize) { - this(_createCache(maxSize)); + this(new LRUMap<>(Math.min(64, maxSize>>2), maxSize)); } /** @@ -119,24 +119,6 @@ public void flushCachedDeserializers() { _cachedDeserializers.clear(); } - /** - * Constructs and returns {@link LookupCache} instance with default settings. - * - * @since 2.16 - */ - public static LookupCache> defaultCache() { - return _createCache(DEFAULT_MAX_CACHE_SIZE); - } - - /** - * Internal method to create actual cache instance for {@link #_cachedDeserializers} - * - * @since 2.16 - */ - private static LookupCache> _createCache(int maxSize) { - return new LRUMap<>(Math.min(64, maxSize>>2), maxSize); - } - /* /********************************************************** /* General deserializer locating method From 6c07b0ea75c490c3250486a93c0dd13f9e270462 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 3 Sep 2023 17:49:22 +0900 Subject: [PATCH 44/53] Remove now invalid JavaDoc WARNING --- .../jackson/databind/cfg/DefaultCacheProvider.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 2669c6e683..5ef8101535 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -7,16 +7,10 @@ import com.fasterxml.jackson.databind.util.LRUMap; import com.fasterxml.jackson.databind.util.LookupCache; -import java.util.Objects; - /** * Default implementation of {@link CacheProvider}. * Provides builder-based custom cache configuration using {@link DefaultCacheProvider.Builder}. * Users can either use this class or implement their own {@link CacheProvider} imlementation. - *

- * WARNING: Configured cache instances are
shared. - * Meaning that if you use same {@link DefaultCacheProvider} instance to construct multiple - * {@link com.fasterxml.jackson.databind.ObjectMapper} instances, they will share the same cache instances. * * @since 2.16 */ From a8458efc6a0cbc33ef99ffd4078cbdd034ee7c7b Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 3 Sep 2023 18:21:59 +0900 Subject: [PATCH 45/53] Clean up changes and fix namings --- .../databind/DeserializationContext.java | 2 +- .../jackson/databind/cfg/CacheProvider.java | 2 +- .../databind/cfg/DefaultCacheProvider.java | 68 +++++++++---------- .../databind/cfg/CacheProviderTest.java | 43 +++++++----- 4 files changed, 62 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index 19237be32c..ff68769f86 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -203,7 +203,7 @@ protected DeserializationContext(DeserializationContext src, * @since 2.16 */ protected DeserializationContext(DeserializationContext src, - DeserializerCache cache) + DeserializerCache cache) { _cache = cache; _factory = src._factory; diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java index a134c857e1..d1a8487dbc 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/CacheProvider.java @@ -10,7 +10,7 @@ * Interface that defines API Jackson uses for constructing various internal * caches. This allows configuring custom caches and cache configurations. * A {@link CacheProvider} instance will be configured through a builder such as - * {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)}. + * {@link com.fasterxml.jackson.databind.json.JsonMapper.Builder#cacheProvider(CacheProvider)} * * @since 2.16 */ diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index 5ef8101535..a4200c8904 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -8,10 +8,11 @@ import com.fasterxml.jackson.databind.util.LookupCache; /** - * Default implementation of {@link CacheProvider}. - * Provides builder-based custom cache configuration using {@link DefaultCacheProvider.Builder}. - * Users can either use this class or implement their own {@link CacheProvider} imlementation. - * + * The default implementation of {@link CacheProvider}. + * Configuration is builder-based via {@link DefaultCacheProvider.Builder}. + *

+ * Users can either use this class or create their own {@link CacheProvider} implementation. + * * @since 2.16 */ public class DefaultCacheProvider @@ -20,10 +21,11 @@ public class DefaultCacheProvider private static final long serialVersionUID = 1L; /** - * Size of {@link LookupCache} instance to create when {@link #forDeserializerCache(DeserializationConfig)} - * is invoked. + * Maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}. + * + * @see Builder#maxDeserializerCacheSize(int) */ - protected final int _deserializerCacheSize; + protected final int _maxDeserializerCacheSize; /* /********************************************************************** @@ -33,7 +35,7 @@ public class DefaultCacheProvider protected DefaultCacheProvider(int deserializerCache) { - _deserializerCacheSize = deserializerCache; + _maxDeserializerCacheSize = deserializerCache; } /* @@ -43,7 +45,7 @@ protected DefaultCacheProvider(int deserializerCache) */ /** - * @return Default {@link DefaultCacheProvider} instance with default configuration values. + * @return Default {@link DefaultCacheProvider} instance using default configuration values. */ public static CacheProvider defaultInstance() { return new DefaultCacheProvider(DeserializerCache.DEFAULT_MAX_CACHE_SIZE); @@ -51,72 +53,68 @@ public static CacheProvider defaultInstance() { /* /********************************************************** - /* Cache accessors + /* Overriden methods /********************************************************** */ @Override public LookupCache> forDeserializerCache(DeserializationConfig config) { - return new LRUMap<>(Math.min(64, _deserializerCacheSize >> 2), _deserializerCacheSize); + return new LRUMap<>(Math.min(64, _maxDeserializerCacheSize >> 2), _maxDeserializerCacheSize); } /* /********************************************************** - /* Configuration using Builder + /* Builder Config /********************************************************** */ /** - * @return Builder instance to construct {@link DefaultCacheProvider} instance. + * @return {@link Builder} instance for configuration. */ public static DefaultCacheProvider.Builder builder() { return new Builder(); } /** - * Builder class to construct {@link DefaultCacheProvider} instance - * and to keep {@link DefaultCacheProvider} immutable. + * Builder offering fluent factory methods to configure {@link DefaultCacheProvider}, keeping it immutable. */ public static class Builder { /** - * Size of {@link LookupCache} instance to create when {@link #forDeserializerCache(DeserializationConfig)} - * is invoked. - * Counter part of {@link DefaultCacheProvider#_deserializerCacheSize}. + * Maximum Size of the {@link LookupCache} instance created by {@link #forDeserializerCache(DeserializationConfig)}. + * Corresponds to {@link DefaultCacheProvider#_maxDeserializerCacheSize}. */ - private int _deserializerCacheSize; + private int _maxDeserializerCacheSize; private Builder() { } /** - * Configures the size of {@link LookupCache} instance to create when {@link #forDeserializerCache(DeserializationConfig)} is invoked. - * Currently, the cache instance is constructed as + * Define the maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}. + * The cache is instantiated as: *

-         *     new LRUMap<>(Math.min(64, size >> 2), size)
+         *     return new LRUMap<>(Math.min(64, maxSize >> 2), maxSize);
          * 
- * ...such in {@link #forDeserializerCache(DeserializationConfig)} - * - * @param deserializerCacheSize Size of {@link LookupCache} instance to construct for {@link DeserializerCache} + * + * @param maxDeserializerCacheSize Size for the {@link LookupCache} to use within {@link DeserializerCache} * @return this builder - * @throws IllegalArgumentException if the {@code deserializerCacheSize} is negative value + * @throws IllegalArgumentException if {@code maxDeserializerCacheSize} is negative * @since 2.16 */ - public Builder deserializerCacheSize(int deserializerCacheSize) { - if (deserializerCacheSize < 0) { - throw new IllegalArgumentException("Cannot set deserializerCacheSize to a negative value"); + public Builder maxDeserializerCacheSize(int maxDeserializerCacheSize) { + if (maxDeserializerCacheSize < 0) { + throw new IllegalArgumentException("Cannot set maxDeserializerCacheSize to a negative value"); } - _deserializerCacheSize = deserializerCacheSize; + _maxDeserializerCacheSize = maxDeserializerCacheSize; return this; } /** - * Constructs and returns a {@link DefaultCacheProvider} instance with given configuration. - * If any of the configuration is not set, it will use default configuration. - * - * @return Constructs and returns a {@link DefaultCacheProvider} instance with given configuration + * Constructs a {@link DefaultCacheProvider} with the provided configuration values, using defaults where not specified. + * + * @return A {@link DefaultCacheProvider} instance with the specified configuration */ public DefaultCacheProvider build() { - return new DefaultCacheProvider(_deserializerCacheSize); + return new DefaultCacheProvider(_maxDeserializerCacheSize); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 474a4da991..83049b9208 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.deser.DeserializerCache; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.util.LookupCache; import org.junit.Before; @@ -99,10 +98,10 @@ public void setUp() { } @Test - public void testDefaultCacheProviderConfig() throws Exception + public void testDefaultCacheProviderConfigDeserializerCache() throws Exception { CacheProvider cacheProvider = DefaultCacheProvider.builder() - .deserializerCacheSize(1234) + .maxDeserializerCacheSize(1234) .build(); ObjectMapper mapper = JsonMapper.builder() .cacheProvider(cacheProvider).build(); @@ -110,6 +109,31 @@ public void testDefaultCacheProviderConfig() throws Exception assertNotNull(mapper.readValue("{\"point\":24}", RandomBean.class)); } + @Test + public void testDefaultCacheProviderConfigDeserializerCacheSizeZero() throws Exception + { + CacheProvider cacheProvider = DefaultCacheProvider.builder() + .maxDeserializerCacheSize(0) + .build(); + ObjectMapper mapper = JsonMapper.builder() + .cacheProvider(cacheProvider) + .build(); + + assertNotNull(mapper.readValue("{\"point\":24}", RandomBean.class)); + } + + @Test + public void testBuilderNullCheckingForDeserializerCacheConfig() throws Exception + { + try { + DefaultCacheProvider.builder() + .maxDeserializerCacheSize(-1); + fail("Should not reach here"); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains("Cannot set maxDeserializerCacheSize to a negative value")); + } + } + @Test public void testCustomCacheProviderConfig() throws Exception { @@ -146,19 +170,6 @@ public void testDefaultCacheProviderSharesCache() throws Exception assertEquals(2, createdCaches.size()); } - - @Test - public void testBuilderNullCheckingForDeserializerCacheConfig() throws Exception - { - try { - DefaultCacheProvider.builder() - .deserializerCacheSize(-1); - fail("Should not reach here"); - } catch (IllegalArgumentException e) { - assertTrue(e.getMessage().contains("Cannot set deserializerCacheSize to a negative value")); - } - } - @Test public void testBuilderBuildWithDefaults() throws Exception { From 0627eee4af930be03e170fea6813ce0923eef3a4 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Sun, 3 Sep 2023 18:27:43 +0900 Subject: [PATCH 46/53] Add more doc --- .../jackson/databind/cfg/DefaultCacheProvider.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index a4200c8904..a00b43f975 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -56,7 +56,13 @@ public static CacheProvider defaultInstance() { /* Overriden methods /********************************************************** */ - + + /** + * Method to provide a {@link LookupCache} instance for constructing {@link DeserializerCache}. + * Implementation should match {@link DeserializerCache#DeserializerCache(int)}. + * + * @return {@link LookupCache} instance for constructing {@link DeserializerCache}. + */ @Override public LookupCache> forDeserializerCache(DeserializationConfig config) { return new LRUMap<>(Math.min(64, _maxDeserializerCacheSize >> 2), _maxDeserializerCacheSize); @@ -116,6 +122,5 @@ public Builder maxDeserializerCacheSize(int maxDeserializerCacheSize) { public DefaultCacheProvider build() { return new DefaultCacheProvider(_maxDeserializerCacheSize); } - } } From 1b5d819f1da2b06784914ba80fee0b62e4ff9c13 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 4 Sep 2023 12:18:21 -0700 Subject: [PATCH 47/53] Minor streamlining --- .../databind/cfg/DefaultCacheProvider.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java index a00b43f975..6859889725 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/DefaultCacheProvider.java @@ -20,6 +20,9 @@ public class DefaultCacheProvider { private static final long serialVersionUID = 1L; + private final static DefaultCacheProvider DEFAULT + = new DefaultCacheProvider(DeserializerCache.DEFAULT_MAX_CACHE_SIZE); + /** * Maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}. * @@ -37,7 +40,7 @@ protected DefaultCacheProvider(int deserializerCache) { _maxDeserializerCacheSize = deserializerCache; } - + /* /********************************************************************** /* Defaults @@ -48,12 +51,12 @@ protected DefaultCacheProvider(int deserializerCache) * @return Default {@link DefaultCacheProvider} instance using default configuration values. */ public static CacheProvider defaultInstance() { - return new DefaultCacheProvider(DeserializerCache.DEFAULT_MAX_CACHE_SIZE); + return DEFAULT; } - + /* /********************************************************** - /* Overriden methods + /* API implementation /********************************************************** */ @@ -65,7 +68,20 @@ public static CacheProvider defaultInstance() { */ @Override public LookupCache> forDeserializerCache(DeserializationConfig config) { - return new LRUMap<>(Math.min(64, _maxDeserializerCacheSize >> 2), _maxDeserializerCacheSize); + return _buildCache(_maxDeserializerCacheSize); + } + + /* + /********************************************************** + /* Overridable factory methods + /********************************************************** + */ + + protected LookupCache _buildCache(int maxSize) + { + // Use 1/4 of maximum size (but at most 64) for initial size + final int initialSize = Math.min(64, maxSize >> 2); + return new LRUMap<>(initialSize, maxSize); } /* @@ -91,8 +107,8 @@ public static class Builder { * Corresponds to {@link DefaultCacheProvider#_maxDeserializerCacheSize}. */ private int _maxDeserializerCacheSize; - - private Builder() { } + + Builder() { } /** * Define the maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}. From 32c0abed88e9644f3d58a2be58188d10ced29f9a Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 5 Sep 2023 05:50:32 +0900 Subject: [PATCH 48/53] Apply review. Fail fast in CacheProviderTest.java --- .../com/fasterxml/jackson/databind/cfg/CacheProviderTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 83049b9208..8a8be95a3c 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -176,7 +176,7 @@ public void testBuilderBuildWithDefaults() throws Exception try { DefaultCacheProvider.builder().build(); } catch (IllegalArgumentException e) { - fail("Should not reach here"); + // expected path } } } From 97e9041f5f03b215dcd82e1dd23440de41c96134 Mon Sep 17 00:00:00 2001 From: "Kim, Joo Hyuk" Date: Tue, 5 Sep 2023 05:53:59 +0900 Subject: [PATCH 49/53] Update CacheProviderTest.java --- .../fasterxml/jackson/databind/cfg/CacheProviderTest.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 8a8be95a3c..a67bec6254 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -173,10 +173,7 @@ public void testDefaultCacheProviderSharesCache() throws Exception @Test public void testBuilderBuildWithDefaults() throws Exception { - try { - DefaultCacheProvider.builder().build(); - } catch (IllegalArgumentException e) { - // expected path - } + // does not throw + DefaultCacheProvider.builder().build(); } } From 0abfb1ab8d285cf5bb9762beef08b0b52a412969 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 5 Sep 2023 09:02:51 +0900 Subject: [PATCH 50/53] Apply review : make CustomCacheProvider in test stateful --- .../databind/cfg/CacheProviderTest.java | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index a67bec6254..1897d06c85 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -36,12 +36,13 @@ static class AnotherBean { static class SimpleTestCache implements LookupCache> { final HashMap> _cachedDeserializers; + + boolean invoked = false; public SimpleTestCache(int cacheSize) { _cachedDeserializers = new HashMap<>(cacheSize); - createdCaches.add(_cachedDeserializers); } - + @Override public int size() { return _cachedDeserializers.size(); @@ -69,13 +70,29 @@ public JsonDeserializer putIfAbsent(JavaType key, JsonDeserializer> forDeserializerCache(DeserializationConfig config) { - invoked = true; - return new SimpleTestCache(123); + createCacheCount++; + return _cache; + } + + int createCacheCount() { + return createCacheCount; } } @@ -84,19 +101,7 @@ public LookupCache> forDeserializerCache(Dese /* Unit tests /********************************************************************** */ - - // For checking CustomCacheProvider.forDeserializerCache() was actually used - private static boolean invoked = false; - - // For checking the cache was actually created - private static final List>> createdCaches = new ArrayList<>(); - @Before - public void setUp() { - createdCaches.clear(); - invoked = false; - } - @Test public void testDefaultCacheProviderConfigDeserializerCache() throws Exception { @@ -137,12 +142,13 @@ public void testBuilderNullCheckingForDeserializerCacheConfig() throws Exception @Test public void testCustomCacheProviderConfig() throws Exception { + SimpleTestCache cache = new SimpleTestCache(123); ObjectMapper mapper = JsonMapper.builder() - .cacheProvider(new CustomCacheProvider()) + .cacheProvider(new CustomCacheProvider(cache)) .build(); - assertTrue(invoked); assertNotNull(mapper.readValue("{\"point\":24}", RandomBean.class)); + assertTrue(cache.isInvoked()); } @Test @@ -150,8 +156,7 @@ public void testDefaultCacheProviderSharesCache() throws Exception { // Arrange // 1. shared CacheProvider - CacheProvider cacheProvider = new CustomCacheProvider(); - + CustomCacheProvider cacheProvider = new CustomCacheProvider(new SimpleTestCache(123)); // 2. two different mapper instances ObjectMapper mapper1 = JsonMapper.builder() .cacheProvider(cacheProvider) @@ -167,7 +172,7 @@ public void testDefaultCacheProviderSharesCache() throws Exception // Assert // 4. Should have created two cache instance - assertEquals(2, createdCaches.size()); + assertEquals(2, cacheProvider.createCacheCount()); } @Test From caabffafb63fb79945d22e275c59ebd98cb8dd96 Mon Sep 17 00:00:00 2001 From: joohyukkim Date: Tue, 5 Sep 2023 09:21:21 +0900 Subject: [PATCH 51/53] Make variables more meaningful --- .../databind/cfg/CacheProviderTest.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java index 1897d06c85..a9c0a6738a 100644 --- a/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/cfg/CacheProviderTest.java @@ -6,13 +6,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.util.LookupCache; -import org.junit.Before; import org.junit.Test; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import java.util.Map; import static org.junit.jupiter.api.Assertions.*; @@ -37,7 +33,7 @@ static class SimpleTestCache implements LookupCache> _cachedDeserializers; - boolean invoked = false; + boolean invokedAtLeastOnce = false; public SimpleTestCache(int cacheSize) { _cachedDeserializers = new HashMap<>(cacheSize); @@ -50,19 +46,19 @@ public int size() { @Override public JsonDeserializer get(Object key) { - invoked = true; + invokedAtLeastOnce = true; return _cachedDeserializers.get(key); } @Override public JsonDeserializer put(JavaType key, JsonDeserializer value) { - invoked = true; + invokedAtLeastOnce = true; return _cachedDeserializers.put(key, value); } @Override public JsonDeserializer putIfAbsent(JavaType key, JsonDeserializer value) { - invoked = true; + invokedAtLeastOnce = true; return _cachedDeserializers.putIfAbsent(key, value); } @@ -71,8 +67,8 @@ public void clear() { _cachedDeserializers.clear(); } - boolean isInvoked() { - return invoked; + boolean isInvokedAtLeastOnce() { + return invokedAtLeastOnce; } } @@ -148,7 +144,7 @@ public void testCustomCacheProviderConfig() throws Exception .build(); assertNotNull(mapper.readValue("{\"point\":24}", RandomBean.class)); - assertTrue(cache.isInvoked()); + assertTrue(cache.isInvokedAtLeastOnce()); } @Test From 6231c7fe6237e7820dfdeb4cfa685fd3e68d9936 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 4 Sep 2023 17:45:53 -0700 Subject: [PATCH 52/53] Minor tweaking to try to unify construction of DeserializerCache for DeserializationContext --- .../jackson/databind/DeserializationContext.java | 14 ++------------ .../deser/DefaultDeserializationContext.java | 11 +++++++---- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index ff68769f86..eee5afc67a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -161,21 +161,11 @@ public abstract class DeserializationContext /********************************************************** */ - protected DeserializationContext(DeserializerFactory df) { - this(df, null); - } - protected DeserializationContext(DeserializerFactory df, DeserializerCache cache) { - if (df == null) { - throw new NullPointerException("Cannot pass null DeserializerFactory"); - } - _factory = df; - if (cache == null) { - cache = new DeserializerCache(); - } - _cache = cache; + _factory = Objects.requireNonNull(df); + _cache = Objects.requireNonNull(cache); _featureFlags = 0; _readCapabilities = null; _config = null; diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 418b52dd59..1fdc8bdafb 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -71,6 +71,8 @@ protected DefaultDeserializationContext(DefaultDeserializationContext src, } /** + * Copy-constructor + * * @since 2.4.4 */ protected DefaultDeserializationContext(DefaultDeserializationContext src) { @@ -400,7 +402,9 @@ public final static class Impl extends DefaultDeserializationContext * {@link DeserializerCache}, given factory. */ public Impl(DeserializerFactory df) { - super(df, null); + // 04-Sep-2023, tatu: Not ideal (wrt not going via CacheProvider) but + // has to do for backwards compatibility: + super(df, new DeserializerCache()); } private Impl(Impl src, @@ -450,9 +454,8 @@ public DefaultDeserializationContext with(DeserializerFactory factory) { @Override // Since 2.16 public DefaultDeserializationContext withCaches(CacheProvider cacheProvider) { - DeserializerCache deserializerCache = new DeserializerCache(cacheProvider.forDeserializerCache(_config)); - - return new Impl(this, deserializerCache); + return new Impl(this, + new DeserializerCache(cacheProvider.forDeserializerCache(_config))); } } } From 232f7aaa3da482864d8c8f03104842a46d3a5300 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 4 Sep 2023 18:13:28 -0700 Subject: [PATCH 53/53] Final touches to try to ensure ObjectMapper.copy() works with caches too --- .../jackson/databind/DeserializationContext.java | 8 +++++--- .../jackson/databind/deser/DeserializerCache.java | 7 +++++++ .../fasterxml/jackson/databind/util/LRUMap.java | 8 +++++++- .../jackson/databind/util/LookupCache.java | 14 +++++++++++++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java index eee5afc67a..c2dd470085 100644 --- a/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/DeserializationContext.java @@ -251,17 +251,19 @@ protected DeserializationContext(DeserializationContext src, } /** - * Copy-constructor for use with copy() by {@link ObjectMapper#copy()} + * Copy-constructor for use with copy() by {@link ObjectMapper#copy()}. + * Only called on blueprint objects. */ protected DeserializationContext(DeserializationContext src) { - _cache = new DeserializerCache(); + _cache = src._cache.emptyCopy(); _factory = src._factory; _config = src._config; _featureFlags = src._featureFlags; _readCapabilities = src._readCapabilities; _view = src._view; - _injectableValues = null; + _injectableValues = src._injectableValues; + _attributes = null; } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java index 9c067e43ab..e4ce196714 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java @@ -73,6 +73,13 @@ public DeserializerCache(LookupCache> cache) _cachedDeserializers = cache; } + /** + * @since 2.16 + */ + public DeserializerCache emptyCopy() { + return new DeserializerCache(_cachedDeserializers.emptyCopy()); + } + /* /********************************************************** /* JDK serialization handling diff --git a/src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java b/src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java index f8428ce8cc..fa6f1fae18 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java @@ -15,7 +15,7 @@ * Since Jackson 2.12, there has been pluggable {@link LookupCache} interface which * allows users, frameworks, provide their own cache implementations. *

- * Snce Jackson 2.14, the implementation + * Since Jackson 2.14, the implementation *

    *
  • Evicts the least recently used entry when max size is reached *
  • @@ -45,6 +45,12 @@ public LRUMap(int initialEntries, int maxEntries) .build(); } + // @since 2.16 + @Override + public LookupCache emptyCopy() { + return new LRUMap(_initialEntries, _maxEntries); + } + @Override public V put(K key, V value) { return _map.put(key, value); diff --git a/src/main/java/com/fasterxml/jackson/databind/util/LookupCache.java b/src/main/java/com/fasterxml/jackson/databind/util/LookupCache.java index 1abb2ebc3e..4ce5172fa0 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/LookupCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/LookupCache.java @@ -9,8 +9,20 @@ * * @since 2.12 (for forwards-compatiblity with 3.0) */ -public interface LookupCache +public interface LookupCache { + /** + * Method needed for creating clones but without contents. + *

    + * Default implementation th + * + * @since 2.16 + */ + default LookupCache emptyCopy() { + throw new UnsupportedOperationException("LookupCache implementation " + +getClass().getName()+" does not implement `emptyCopy()`"); + } + /** * @return Number of entries currently in cache: may be approximate, only * to be used for diagnostics, metrics reporting