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 configureSerializerCache Jackson uses #4111

Merged
merged 16 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -2296,6 +2296,7 @@ public ObjectMapper setCacheProvider(CacheProvider cacheProvider) {
_deserializationConfig = _deserializationConfig.with(cacheProvider);
_serializationConfig = _serializationConfig.with(cacheProvider);
_deserializationContext = _deserializationContext.withCaches(cacheProvider);
_serializerProvider = _serializerProvider.withCaches(cacheProvider);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,28 @@ protected SerializerProvider(SerializerProvider src)
_stdNullValueSerializer = src._stdNullValueSerializer;
}


/**
* @since 2.16
*/
protected SerializerProvider(SerializerProvider src, SerializerCache serializerCache)
{
_serializerCache = serializerCache;

_config = src._config;
_serializationView = src._serializationView;
_serializerFactory = src._serializerFactory;
_attributes = src._attributes;

_knownSerializers = src._knownSerializers;
_unknownTypeSerializer = src._unknownTypeSerializer;

_nullValueSerializer = src._nullValueSerializer;
_nullKeySerializer = src._nullKeySerializer;
_keySerializer = src._keySerializer;
_stdNullValueSerializer = src._stdNullValueSerializer;
}

/*
/**********************************************************
/* Methods for configuring default settings
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
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.*;
import com.fasterxml.jackson.databind.deser.DeserializerCache;
import com.fasterxml.jackson.databind.util.LookupCache;
import com.fasterxml.jackson.databind.util.TypeKey;

/**
* Interface that defines API Jackson uses for constructing various internal
Expand All @@ -24,4 +23,10 @@ public interface CacheProvider
*/
LookupCache<JavaType, JsonDeserializer<Object>> forDeserializerCache(DeserializationConfig config);

/**
* Method to provide a {@link LookupCache} instance for constructing {@link com.fasterxml.jackson.databind.ser.SerializerCache}.
*
* @return {@link LookupCache} instance for constructing {@link com.fasterxml.jackson.databind.ser.SerializerCache}.
*/
LookupCache<TypeKey, JsonSerializer<Object>> forSerializerCache(SerializationConfig config);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
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.*;
import com.fasterxml.jackson.databind.deser.DeserializerCache;
import com.fasterxml.jackson.databind.ser.SerializerCache;
import com.fasterxml.jackson.databind.util.LRUMap;
import com.fasterxml.jackson.databind.util.LookupCache;
import com.fasterxml.jackson.databind.util.TypeKey;

/**
* The default implementation of {@link CacheProvider}.
Expand All @@ -21,24 +21,32 @@ public class DefaultCacheProvider
private static final long serialVersionUID = 1L;

private final static DefaultCacheProvider DEFAULT
= new DefaultCacheProvider(DeserializerCache.DEFAULT_MAX_CACHE_SIZE);
= new DefaultCacheProvider(DeserializerCache.DEFAULT_MAX_CACHE_SIZE, SerializerCache.DEFAULT_MAX_CACHE_SIZE);

/**
* Maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}.
*
* @see Builder#maxDeserializerCacheSize(int)
*/
protected final int _maxDeserializerCacheSize;

/**
* Maximum size of the {@link LookupCache} instance constructed by {@link #forSerializerCache(SerializationConfig)}
*
* @see Builder#maxSerializerCacheSize(int)
*/
protected final int _maxSerializerCacheSize;

/*
/**********************************************************************
/* Life cycle
/**********************************************************************
*/

protected DefaultCacheProvider(int deserializerCache)
protected DefaultCacheProvider(int maxDeserializerCacheSize, int maxSerializerCacheSize)
{
_maxDeserializerCacheSize = deserializerCache;
_maxDeserializerCacheSize = maxDeserializerCacheSize;
_maxSerializerCacheSize = maxSerializerCacheSize;
}

/*
Expand Down Expand Up @@ -71,6 +79,11 @@ public LookupCache<JavaType, JsonDeserializer<Object>> forDeserializerCache(Dese
return _buildCache(_maxDeserializerCacheSize);
}

@Override
public LookupCache<TypeKey, JsonSerializer<Object>> forSerializerCache(SerializationConfig config) {
return _buildCache(_maxSerializerCacheSize);
}

/*
/**********************************************************
/* Overridable factory methods
Expand Down Expand Up @@ -108,14 +121,17 @@ public static class Builder {
*/
private int _maxDeserializerCacheSize;

/**
* Maximum Size of the {@link LookupCache} instance created by {@link #forSerializerCache(SerializationConfig)}
* Corresponds to {@link DefaultCacheProvider#_maxSerializerCacheSize}.
*/
private int _maxSerializerCacheSize;

Builder() { }

/**
* Define the maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}.
* The cache is instantiated as:
* <pre>
* return new LRUMap<>(Math.min(64, maxSize >> 2), maxSize);
* </pre>
* Define the maximum size of the {@link LookupCache} instance constructed by {@link #forDeserializerCache(DeserializationConfig)}
* and {@link #_buildCache(int)}.
*
* @param maxDeserializerCacheSize Size for the {@link LookupCache} to use within {@link DeserializerCache}
* @return this builder
Expand All @@ -130,13 +146,30 @@ public Builder maxDeserializerCacheSize(int maxDeserializerCacheSize) {
return this;
}

/**
* Define the maximum size of the {@link LookupCache} instance constructed by {@link #forSerializerCache(SerializationConfig)}
* and {@link #_buildCache(int)}
*
* @param maxSerializerCacheSize Size for the {@link LookupCache} to use within {@link SerializerCache}
* @return this builder
* @throws IllegalArgumentException if {@code maxSerializerCacheSize} is negative
* @since 2.16
*/
public Builder maxSerializerCacheSize(int maxSerializerCacheSize) {
if (maxSerializerCacheSize < 0) {
throw new IllegalArgumentException("Cannot set maxSerializerCacheSize to a negative value");
}
_maxSerializerCacheSize = maxSerializerCacheSize;
return this;
}

/**
* 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(_maxDeserializerCacheSize);
return new DefaultCacheProvider(_maxDeserializerCacheSize, _maxSerializerCacheSize);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
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.deser.DefaultDeserializationContext;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
Expand Down Expand Up @@ -73,6 +75,15 @@ protected DefaultSerializerProvider(DefaultSerializerProvider src) {
super(src);
}

/**
* @since 2.16
*/
protected DefaultSerializerProvider(DefaultSerializerProvider src,
CacheProvider cp) {
super(src,
new SerializerCache(cp.forSerializerCache(src._config)));
}

/**
* Method that sub-classes need to implement: used to create a non-blueprint instances
* from the blueprint.
Expand Down Expand Up @@ -173,6 +184,19 @@ public boolean includeFilterSuppressNulls(Object filter) throws JsonMappingExcep
}
}

/*
/**********************************************************
/* Extended API, life-cycle
/**********************************************************
*/

/**
* Fluent factory method used for constructing a new instance with cache instances provided by {@link CacheProvider}.
*
* @since 2.16
*/
public abstract DefaultSerializerProvider withCaches(CacheProvider cacheProvider);

/*
/**********************************************************
/* Object Id handling
Expand Down Expand Up @@ -592,7 +616,6 @@ public com.fasterxml.jackson.databind.jsonschema.JsonSchema generateJsonSchema(C
return new com.fasterxml.jackson.databind.jsonschema.JsonSchema((ObjectNode) schemaNode);
}


/*
/**********************************************************
/* Helper classes
Expand All @@ -614,6 +637,13 @@ protected Impl(SerializerProvider src, SerializationConfig config,
super(src, config, f);
}

/**
* @since 2.16
*/
protected Impl(Impl src, CacheProvider cp) {
super(src, cp);
}

@Override
public DefaultSerializerProvider copy()
{
Expand All @@ -624,5 +654,10 @@ public DefaultSerializerProvider copy()
public Impl createInstance(SerializationConfig config, SerializerFactory jsf) {
return new Impl(this, config, jsf);
}

@Override
public DefaultSerializerProvider withCaches(CacheProvider cp) {
return new Impl(this, cp);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.ser.impl.ReadOnlyClassToSerializerMap;
import com.fasterxml.jackson.databind.util.LRUMap;
import com.fasterxml.jackson.databind.util.LookupCache;
import com.fasterxml.jackson.databind.util.TypeKey;

/**
Expand All @@ -28,29 +29,36 @@ public final class SerializerCache
* By default, allow caching of up to 4000 serializer entries (for possibly up to
* 1000 types; but depending access patterns may be as few as half of that).
*/
public final static int DEFAULT_MAX_CACHED = 4000;
cowtowncoder marked this conversation as resolved.
Show resolved Hide resolved
public final static int DEFAULT_MAX_CACHE_SIZE = 4000;

/**
* Shared, modifiable map; all access needs to be through synchronized blocks.
*<p>
* NOTE: keys are of various types (see below for key types), in addition to
* basic {@link JavaType} used for "untyped" serializers.
*/
private final LRUMap<TypeKey, JsonSerializer<Object>> _sharedMap;
private final LookupCache<TypeKey, JsonSerializer<Object>> _sharedMap;

/**
* Most recent read-only instance, created from _sharedMap, if any.
*/
private final AtomicReference<ReadOnlyClassToSerializerMap> _readOnlyMap;
private final AtomicReference<ReadOnlyClassToSerializerMap> _readOnlyMap =
new AtomicReference<ReadOnlyClassToSerializerMap>();

public SerializerCache() {
this(DEFAULT_MAX_CACHED);
this(DEFAULT_MAX_CACHE_SIZE);
}

public SerializerCache(int maxCached) {
int initial = Math.min(64, maxCached>>2);
_sharedMap = new LRUMap<TypeKey, JsonSerializer<Object>>(initial, maxCached);
_readOnlyMap = new AtomicReference<ReadOnlyClassToSerializerMap>();
}

/**
* @since 2.16
*/
public SerializerCache(LookupCache<TypeKey, JsonSerializer<Object>> cache) {
_sharedMap = cache;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.util.LRUMap;
import com.fasterxml.jackson.databind.util.LookupCache;
import com.fasterxml.jackson.databind.util.TypeKey;

/**
Expand All @@ -22,7 +23,7 @@ public final class ReadOnlyClassToSerializerMap

private final int _mask;

public ReadOnlyClassToSerializerMap(LRUMap<TypeKey,JsonSerializer<Object>> src)
public ReadOnlyClassToSerializerMap(LookupCache<TypeKey,JsonSerializer<Object>> src)
{
_size = findSize(src.size());
_mask = (_size-1);
Expand All @@ -48,7 +49,7 @@ private final static int findSize(int size)
/**
* Factory method for constructing an instance.
*/
public static ReadOnlyClassToSerializerMap from(LRUMap<TypeKey, JsonSerializer<Object>> src) {
public static ReadOnlyClassToSerializerMap from(LookupCache<TypeKey, JsonSerializer<Object>> src) {
return new ReadOnlyClassToSerializerMap(src);
}

Expand Down
Loading