Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way to configure DeserializerCache Jackson uses #4101

Merged
merged 65 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
b1a1519
First draft
JooHyukKim Aug 28, 2023
3b0818a
Change name
JooHyukKim Aug 28, 2023
6bf55c2
Apply review
JooHyukKim Aug 29, 2023
d49dbb3
Clean up changes
JooHyukKim Aug 29, 2023
c71779f
Fix DeserializationConfig constructor accessor
JooHyukKim Aug 29, 2023
ea77d79
Clean up commented out code
JooHyukKim Aug 29, 2023
f2b43c4
Create interface for CacheProvider
JooHyukKim Aug 29, 2023
7cefce2
Merge branch '2.16' into 2502-poc
cowtowncoder Aug 30, 2023
3028b0c
Change DefaultCacheProvider to CacheProvider as param type
JooHyukKim Aug 30, 2023
8a5cbf2
Merge branch '2502-poc' of https://github.com/JooHyukKim/jackson-data…
JooHyukKim Aug 30, 2023
3b53c76
Remove cache mutation in deserialization config
JooHyukKim Aug 30, 2023
64ae831
Update CacheProviderTest.java
JooHyukKim Aug 30, 2023
30adc84
Apply review
JooHyukKim Aug 30, 2023
a36b1d5
not specify _cacheProvider as null
JooHyukKim Aug 30, 2023
272ef1d
Minimize changes
JooHyukKim Aug 30, 2023
a37f740
Remove supplier
JooHyukKim Aug 30, 2023
4359ea3
Merge branch '2.16' into 2502-poc
JooHyukKim Aug 31, 2023
ee5e2e2
Adapt to DeserCache changes
JooHyukKim Aug 31, 2023
7d58ac7
Merge branch '2.16' into 2502-poc
cowtowncoder Aug 31, 2023
a71143c
Merge branch '2.16' into 2502-poc
cowtowncoder Aug 31, 2023
73414ca
WIP apply review
JooHyukKim Aug 31, 2023
11bd54a
Add CacheProvider configuration in BaseSettings
JooHyukKim Aug 31, 2023
c9e7cd1
Update ObjectMapper.java
JooHyukKim Aug 31, 2023
465cc51
Add CacheProvider configuration in BaseSettings
JooHyukKim Aug 31, 2023
05c1d79
Add `BaseSettings`
JooHyukKim Aug 31, 2023
890f416
Add BaseSettings `ObjectMapper.setCacheProvider(CacheProvider cachePr…
JooHyukKim Aug 31, 2023
bc62b04
Merge branch '4101-Add-Cache-Provider-in-BaseSettings' into 2502-poc
JooHyukKim Aug 31, 2023
6f0cd81
Remove supplier
JooHyukKim Aug 31, 2023
447df54
Implement CacheProvider, its default, and related DeserializerCache
JooHyukKim Aug 31, 2023
3e371c9
Implement CacheProvider, its default, and related DeserializerCache
JooHyukKim Aug 31, 2023
49ffff0
Update DefaultDeserializationContext.java
JooHyukKim Aug 31, 2023
054d46f
Fix docs and naming
JooHyukKim Aug 31, 2023
8e229ec
Remove binding of CacheProv in DatabindContext
JooHyukKim Sep 2, 2023
6345e36
Sync changes with sub-PRs
JooHyukKim Sep 2, 2023
578eda9
Minimize changes
JooHyukKim Sep 2, 2023
f3600db
Minor code reuse and access control in DefaultCache.
JooHyukKim Sep 2, 2023
317f8cb
Merge branch '4101-implement-CacheProvider' into 2502-poc
JooHyukKim Sep 2, 2023
e1132d6
Improve JavaDoc
JooHyukKim Sep 2, 2023
e369d0c
Improve Doc and method order
JooHyukKim Sep 2, 2023
2538f6e
Merge branch '2.16' into 2502-poc
JooHyukKim Sep 2, 2023
95b6a2f
Apply review
JooHyukKim Sep 2, 2023
6350496
Update SerializationConfig.java
JooHyukKim Sep 2, 2023
6a7ec46
Remove accessor conflict
JooHyukKim Sep 2, 2023
701d1a5
Update DefaultCacheProvider.java
JooHyukKim Sep 2, 2023
6629f8c
Merge branch '4101-implement-CacheProvider' into 2502-poc
JooHyukKim Sep 2, 2023
aff462e
Minimize more changes.
JooHyukKim Sep 2, 2023
9187533
Solution 2 : Configure CacheProvider when setting CacheProvider
JooHyukKim Sep 2, 2023
68716c8
Improve test and doc around DefaultCacheProvider.Builder
JooHyukKim Sep 2, 2023
b44a8bc
Clean up JavaDoc and add a test
JooHyukKim Sep 2, 2023
70b4558
Apply review on DefaultCacheProvider and CacheProvider
JooHyukKim Sep 3, 2023
7f47132
Implement withCaches
JooHyukKim Sep 3, 2023
3749efd
Revert DeserializerCache changes, except DEFAULT_MAX_CACHE_SIZE constant
JooHyukKim Sep 3, 2023
6c07b0e
Remove now invalid JavaDoc WARNING
JooHyukKim Sep 3, 2023
a8458ef
Clean up changes and fix namings
JooHyukKim Sep 3, 2023
0627eee
Add more doc
JooHyukKim Sep 3, 2023
fc1af99
Merge branch '2.16' into 2502-poc
cowtowncoder Sep 4, 2023
75d6288
Merge branch '2.16' into 2502-poc
cowtowncoder Sep 4, 2023
1b5d819
Minor streamlining
cowtowncoder Sep 4, 2023
32c0abe
Apply review. Fail fast in CacheProviderTest.java
JooHyukKim Sep 4, 2023
97e9041
Update CacheProviderTest.java
JooHyukKim Sep 4, 2023
0abfb1a
Apply review : make CustomCacheProvider in test stateful
JooHyukKim Sep 5, 2023
caabffa
Make variables more meaningful
JooHyukKim Sep 5, 2023
6231c7f
Minor tweaking to try to unify construction of DeserializerCache for …
cowtowncoder Sep 5, 2023
232f7aa
Final touches to try to ensure ObjectMapper.copy() works with caches too
cowtowncoder Sep 5, 2023
bd52023
Merge branch '2.16' into 2502-poc
cowtowncoder Sep 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions src/main/java/com/fasterxml/jackson/databind/CacheProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
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(CacheProvider)}.
*
* @since 2.16
*/
public class CacheProvider
JooHyukKim marked this conversation as resolved.
Show resolved Hide resolved
implements java.io.Serializable
{
private static final long serialVersionUID = 1L; // 2.6

protected LookupCache<JavaType, JsonDeserializer<Object>> _deserializerCache;

protected CacheProvider() { }

protected CacheProvider setDeserializerCache(LookupCache<JavaType, JsonDeserializer<Object>> cache) {
_deserializerCache = cache;
return this;
}

/*
/**********************************************************
/* Builder Initialization
/**********************************************************
*/

public static CacheProvider.Builder builder() {
return new Builder(new CacheProvider());
}

public LookupCache<JavaType, JsonDeserializer<Object>> 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<JavaType, JsonDeserializer<Object>> cache) {
cacheProvider.setDeserializerCache(cache);
return this;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ public final class DeserializationConfig
*/
protected final int _formatReadFeaturesToChange;

/**
* Used to provide custom cache implementation in downstream components.
*
* @since 2.16
*/
protected CacheProvider _cacheProvider;

/*
/**********************************************************
/* Life-cycle, primary constructors for new instances
Expand Down Expand Up @@ -325,6 +332,23 @@ protected DeserializationConfig(DeserializationConfig src,
_formatReadFeaturesToChange = src._formatReadFeaturesToChange;
}

/**
* @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:
protected BaseSettings getBaseSettings() { return _base; }

Expand Down Expand Up @@ -922,6 +946,13 @@ public ConstructorDetector getConstructorDetector() {
return _ctorDetector;
}

/**
* @since 2.16
*/
public CacheProvider getCacheProvider() {
return _cacheProvider;
}

/*
/**********************************************************
/* Introspection methods
Expand Down Expand Up @@ -1046,4 +1077,12 @@ 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);
}
cowtowncoder marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ protected DeserializationContext(DeserializationContext src,
DeserializationConfig config, JsonParser p,
InjectableValues injectableValues)
{
_cache = src._cache;
_cache = src._cache.withCache(config.getCacheProvider());
JooHyukKim marked this conversation as resolved.
Show resolved Hide resolved
_factory = src._factory;
// 08-Jun-2020. tatu: Called only for `ObjectMapper.canDeserialize()`
// (see [databind#2749]), not sure what's the best work-around but
Expand All @@ -230,7 +230,7 @@ protected DeserializationContext(DeserializationContext src,
protected DeserializationContext(DeserializationContext src,
DeserializationConfig config)
{
_cache = src._cache;
_cache = src._cache.withCache(config.getCacheProvider());
_factory = src._factory;
_readCapabilities = null;

Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,16 @@ public ObjectMapper setConstructorDetector(ConstructorDetector cd) {
return this;
}

/**
* Method for specifying {@link CacheProvider} to provide Cache instances to be used in components downstream.
*
* @since 2.16
*/
public ObjectMapper setCacheProvider(CacheProvider cacheProvider) {
_deserializationConfig = _deserializationConfig.withCacheProvider(cacheProvider);
cowtowncoder marked this conversation as resolved.
Show resolved Hide resolved
return this;
}

/**
* Method for adding specified {@link DeserializationProblemHandler}
* to be used for handling specific problems during deserialization.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,14 @@ public B clearProblemHandlers() {
return _this();
}

/**
* @since 2.16
*/
public B cacheProvider(CacheProvider cacheProvider) {
_mapper.setCacheProvider(cacheProvider);
return _this();
}

/*
/**********************************************************************
/* Changing global defaults
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -33,8 +34,10 @@ 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.
* <p>
* Since 2.16, changed its type from {@link LRUMap} to {@link LookupCache}
*/
final protected LRUMap<JavaType, JsonDeserializer<Object>> _cachedDeserializers;
final protected LookupCache<JavaType, JsonDeserializer<Object>> _cachedDeserializers;

/**
* During deserializer construction process we may need to keep track of partially
Expand All @@ -59,6 +62,23 @@ public DeserializerCache(int maxSize) {
_cachedDeserializers = new LRUMap<>(initial, maxSize);
}

/**
* @since 2.16
*/
protected DeserializerCache(LookupCache<JavaType, JsonDeserializer<Object>> cachedDeserializers) {
_cachedDeserializers = cachedDeserializers;
}

/**
* @since 2.16
*/
public DeserializerCache withCache(CacheProvider cacheProvider) {
if (cacheProvider == null) {
return this;
}
return new DeserializerCache(cacheProvider.provideForDeserializerCache());
}

/*
/**********************************************************
/* JDK serialization handling
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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.HashMap;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* <a href="https://github.com/FasterXML/jackson-databind/issues/2502">
* [databind#2502] Test for adding a way to configure Caches Jackson uses</a>
*
* @since 2.16
*/
public class CacheProviderTest
{

static class RandomBean {
public int point;
}

static class SimpleTestCache implements LookupCache<JavaType, JsonDeserializer<Object>> {

final HashMap<JavaType, JsonDeserializer<Object>> cache = new HashMap<>();

@Override
public int size(){
return cache.size();
}

@Override
public JsonDeserializer<Object> get(Object key) {
return cache.get(key);
}

@Override
public JsonDeserializer<Object> put(JavaType key, JsonDeserializer<Object> value) {
return cache.put(key, value);
}

@Override
public JsonDeserializer<Object> putIfAbsent(JavaType key, JsonDeserializer<Object> value) {
return cache.putIfAbsent(key, value);
}

@Override
public void clear() {
cache.clear();
}
}

@Test
public void testCacheConfig() throws Exception
{
CacheProvider cacheProvider = CacheProvider.builder()
.forDeserializerCache(new SimpleTestCache())
.build();

ObjectMapper mapper = JsonMapper.builder().cacheProvider(cacheProvider).build();

RandomBean bean = mapper.readValue("{\"point\":24}", RandomBean.class);
assertEquals(24, bean.point);
}
}