Skip to content

Commit 08a27c9

Browse files
committed
Fix #3311: essentially backporting #1994 from 3.0 to establish limit on serializer cache
1 parent f3ba2d9 commit 08a27c9

File tree

3 files changed

+44
-20
lines changed

3 files changed

+44
-20
lines changed

src/main/java/com/fasterxml/jackson/databind/ser/SerializerCache.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package com.fasterxml.jackson.databind.ser;
22

3-
import java.util.*;
43
import java.util.concurrent.atomic.AtomicReference;
54

65
import com.fasterxml.jackson.databind.*;
76
import com.fasterxml.jackson.databind.ser.impl.ReadOnlyClassToSerializerMap;
7+
import com.fasterxml.jackson.databind.util.LRUMap;
88
import com.fasterxml.jackson.databind.util.TypeKey;
99

1010
/**
@@ -24,22 +24,34 @@
2424
*/
2525
public final class SerializerCache
2626
{
27+
/**
28+
* By default, allow caching of up to 4000 serializer entries (for possibly up to
29+
* 1000 types; but depending access patterns may be as few as half of that).
30+
*/
31+
public final static int DEFAULT_MAX_CACHED = 4000;
32+
2733
/**
2834
* Shared, modifiable map; all access needs to be through synchronized blocks.
2935
*<p>
3036
* NOTE: keys are of various types (see below for key types), in addition to
3137
* basic {@link JavaType} used for "untyped" serializers.
3238
*/
33-
private final HashMap<TypeKey, JsonSerializer<Object>> _sharedMap
34-
= new HashMap<TypeKey, JsonSerializer<Object>>(64);
39+
private final LRUMap<TypeKey, JsonSerializer<Object>> _sharedMap;
3540

3641
/**
3742
* Most recent read-only instance, created from _sharedMap, if any.
3843
*/
39-
private final AtomicReference<ReadOnlyClassToSerializerMap> _readOnlyMap
40-
= new AtomicReference<ReadOnlyClassToSerializerMap>();
44+
private final AtomicReference<ReadOnlyClassToSerializerMap> _readOnlyMap;
4145

42-
public SerializerCache() { }
46+
public SerializerCache() {
47+
this(DEFAULT_MAX_CACHED);
48+
}
49+
50+
public SerializerCache(int maxCached) {
51+
int initial = Math.min(64, maxCached>>2);
52+
_sharedMap = new LRUMap<TypeKey, JsonSerializer<Object>>(initial, maxCached);
53+
_readOnlyMap = new AtomicReference<ReadOnlyClassToSerializerMap>();
54+
}
4355

4456
/**
4557
* Method that can be called to get a read-only instance populated from the

src/main/java/com/fasterxml/jackson/databind/ser/impl/ReadOnlyClassToSerializerMap.java

+9-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
package com.fasterxml.jackson.databind.ser.impl;
22

3-
import java.util.*;
4-
53
import com.fasterxml.jackson.databind.JavaType;
64
import com.fasterxml.jackson.databind.JsonSerializer;
5+
import com.fasterxml.jackson.databind.util.LRUMap;
76
import com.fasterxml.jackson.databind.util.TypeKey;
87

98
/**
@@ -23,17 +22,15 @@ public final class ReadOnlyClassToSerializerMap
2322

2423
private final int _mask;
2524

26-
public ReadOnlyClassToSerializerMap(Map<TypeKey,JsonSerializer<Object>> serializers)
25+
public ReadOnlyClassToSerializerMap(LRUMap<TypeKey,JsonSerializer<Object>> src)
2726
{
28-
int size = findSize(serializers.size());
29-
_size = size;
30-
_mask = (size-1);
31-
Bucket[] buckets = new Bucket[size];
32-
for (Map.Entry<TypeKey,JsonSerializer<Object>> entry : serializers.entrySet()) {
33-
TypeKey key = entry.getKey();
27+
_size = findSize(src.size());
28+
_mask = (_size-1);
29+
Bucket[] buckets = new Bucket[_size];
30+
src.contents((key, value) -> {
3431
int index = key.hashCode() & _mask;
35-
buckets[index] = new Bucket(buckets[index], key, entry.getValue());
36-
}
32+
buckets[index] = new Bucket(buckets[index], key, value);
33+
});
3734
_buckets = buckets;
3835
}
3936

@@ -51,7 +48,7 @@ private final static int findSize(int size)
5148
/**
5249
* Factory method for constructing an instance.
5350
*/
54-
public static ReadOnlyClassToSerializerMap from(HashMap<TypeKey, JsonSerializer<Object>> src) {
51+
public static ReadOnlyClassToSerializerMap from(LRUMap<TypeKey, JsonSerializer<Object>> src) {
5552
return new ReadOnlyClassToSerializerMap(src);
5653
}
5754

src/main/java/com/fasterxml/jackson/databind/util/LRUMap.java

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.fasterxml.jackson.databind.util;
22

3+
import java.util.Map;
4+
import java.util.function.BiConsumer;
5+
36
import com.fasterxml.jackson.databind.util.internal.PrivateMaxEntriesMap;
47

58
/**
@@ -61,9 +64,21 @@ public V putIfAbsent(K key, V value) {
6164
public int size() { return _map.size(); }
6265

6366
/*
64-
/**********************************************************
67+
/**********************************************************************
68+
/* Extended API (2.14)
69+
/**********************************************************************
70+
*/
71+
72+
public void contents(BiConsumer<K,V> consumer) {
73+
for (Map.Entry<K,V> entry : _map.entrySet()) {
74+
consumer.accept(entry.getKey(), entry.getValue());
75+
}
76+
}
77+
78+
/*
79+
/**********************************************************************
6580
/* Serializable overrides
66-
/**********************************************************
81+
/**********************************************************************
6782
*/
6883

6984
protected Object readResolve() {

0 commit comments

Comments
 (0)