diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/SerializerCache.java b/src/main/java/com/fasterxml/jackson/databind/ser/SerializerCache.java index 153a5334bd..54896f9225 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/SerializerCache.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/SerializerCache.java @@ -1,10 +1,10 @@ package com.fasterxml.jackson.databind.ser; -import java.util.*; 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.TypeKey; /** @@ -24,22 +24,34 @@ */ 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; + /** * 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 HashMap> _sharedMap - = new HashMap>(64); + private final LRUMap> _sharedMap; /** * Most recent read-only instance, created from _sharedMap, if any. */ - private final AtomicReference _readOnlyMap - = new AtomicReference(); + private final AtomicReference _readOnlyMap; - public SerializerCache() { } + public SerializerCache() { + this(DEFAULT_MAX_CACHED); + } + + public SerializerCache(int maxCached) { + int initial = Math.min(64, maxCached>>2); + _sharedMap = new LRUMap>(initial, maxCached); + _readOnlyMap = new AtomicReference(); + } /** * Method that can be called to get a read-only instance populated from the diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/ReadOnlyClassToSerializerMap.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/ReadOnlyClassToSerializerMap.java index feacbce21e..7b3531d109 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/ReadOnlyClassToSerializerMap.java +++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/ReadOnlyClassToSerializerMap.java @@ -1,9 +1,8 @@ package com.fasterxml.jackson.databind.ser.impl; -import java.util.*; - 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.TypeKey; /** @@ -23,17 +22,15 @@ public final class ReadOnlyClassToSerializerMap private final int _mask; - public ReadOnlyClassToSerializerMap(Map> serializers) + public ReadOnlyClassToSerializerMap(LRUMap> src) { - int size = findSize(serializers.size()); - _size = size; - _mask = (size-1); - Bucket[] buckets = new Bucket[size]; - for (Map.Entry> entry : serializers.entrySet()) { - TypeKey key = entry.getKey(); + _size = findSize(src.size()); + _mask = (_size-1); + Bucket[] buckets = new Bucket[_size]; + src.contents((key, value) -> { int index = key.hashCode() & _mask; - buckets[index] = new Bucket(buckets[index], key, entry.getValue()); - } + buckets[index] = new Bucket(buckets[index], key, value); + }); _buckets = buckets; } @@ -51,7 +48,7 @@ private final static int findSize(int size) /** * Factory method for constructing an instance. */ - public static ReadOnlyClassToSerializerMap from(HashMap> src) { + public static ReadOnlyClassToSerializerMap from(LRUMap> src) { return new ReadOnlyClassToSerializerMap(src); } 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 2ce8fe3a09..af9f7b79ec 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java @@ -1,5 +1,8 @@ package com.fasterxml.jackson.databind.util; +import java.util.Map; +import java.util.function.BiConsumer; + import com.fasterxml.jackson.databind.util.internal.PrivateMaxEntriesMap; /** @@ -61,9 +64,21 @@ public V putIfAbsent(K key, V value) { public int size() { return _map.size(); } /* - /********************************************************** + /********************************************************************** + /* Extended API (2.14) + /********************************************************************** + */ + + public void contents(BiConsumer consumer) { + for (Map.Entry entry : _map.entrySet()) { + consumer.accept(entry.getKey(), entry.getValue()); + } + } + + /* + /********************************************************************** /* Serializable overrides - /********************************************************** + /********************************************************************** */ protected Object readResolve() {