com.fasterxml.jackson.databind.ser.SerializerCache Maven / Gradle / Ivy
package com.fasterxml.jackson.databind.ser;
import java.util.concurrent.atomic.AtomicReference;
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;
/**
* Simple cache object that allows for doing 2-level lookups: first level is
* by "local" read-only lookup Map (used without locking)
* and second backup level is by a shared modifiable HashMap.
* The idea is that after a while, most serializers are found from the
* local Map (to optimize performance, reduce lock contention),
* but that during buildup we can use a shared map to reduce both
* number of distinct read-only maps constructed, and number of
* serializers constructed.
*
* Cache contains three kinds of entries,
* based on combination of class pair key. First class in key is for the
* type to serialize, and second one is type used for determining how
* to resolve value type. One (but not both) of entries can be null.
*/
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_CACHE_SIZE = 4000;
/**
* @deprecated Use {@link #DEFAULT_MAX_CACHE_SIZE} instead.
*/
@Deprecated
public final static int DEFAULT_MAX_CACHED = DEFAULT_MAX_CACHE_SIZE;
/**
* Shared, modifiable map; all access needs to be through synchronized blocks.
*
* NOTE: keys are of various types (see below for key types), in addition to
* basic {@link JavaType} used for "untyped" serializers.
*/
private final LookupCache> _sharedMap;
/**
* Most recent read-only instance, created from _sharedMap, if any.
*/
private final AtomicReference _readOnlyMap =
new AtomicReference();
public SerializerCache() {
this(DEFAULT_MAX_CACHE_SIZE);
}
public SerializerCache(int maxCached) {
int initial = Math.min(64, maxCached>>2);
_sharedMap = new LRUMap>(initial, maxCached);
}
/**
* @since 2.16
*/
public SerializerCache(LookupCache> cache) {
_sharedMap = cache;
}
/**
* Method that can be called to get a read-only instance populated from the
* most recent version of the shared lookup Map.
*/
public ReadOnlyClassToSerializerMap getReadOnlyLookupMap()
{
ReadOnlyClassToSerializerMap m = _readOnlyMap.get();
if (m != null) {
return m;
}
return _makeReadOnlyLookupMap();
}
private final synchronized ReadOnlyClassToSerializerMap _makeReadOnlyLookupMap() {
// double-locking; safe, but is it really needed? Not doing that is only a perf problem,
// not correctness
ReadOnlyClassToSerializerMap m = _readOnlyMap.get();
if (m == null) {
m = ReadOnlyClassToSerializerMap.from(_sharedMap);
_readOnlyMap.set(m);
}
return m;
}
/*
/**********************************************************
/* Lookup methods for accessing shared (slow) cache
/**********************************************************
*/
public synchronized int size() {
return _sharedMap.size();
}
/**
* Method that checks if the shared (and hence, synchronized) lookup Map might have
* untyped serializer for given type.
*/
public JsonSerializer