Skip to content

Commit 38495cd

Browse files
committed
Merge branch 'master' of github.com:FasterXML/jackson-databind
2 parents d59211a + 654a1a1 commit 38495cd

File tree

11 files changed

+232
-24
lines changed

11 files changed

+232
-24
lines changed

src/main/java/com/fasterxml/jackson/databind/deser/DeserializerCache.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.fasterxml.jackson.databind.type.*;
1212
import com.fasterxml.jackson.databind.util.ClassUtil;
1313
import com.fasterxml.jackson.databind.util.Converter;
14+
import com.fasterxml.jackson.databind.util.LookupCache;
1415
import com.fasterxml.jackson.databind.util.SimpleLookupCache;
1516

1617
/**
@@ -41,7 +42,7 @@ public final class DeserializerCache
4142
* This currently (3.0) means POJO, Enum and Container (collection,
4243
* map) deserializers.
4344
*/
44-
private final SimpleLookupCache<JavaType, JsonDeserializer<Object>> _cachedDeserializers;
45+
private final LookupCache<JavaType, JsonDeserializer<Object>> _cachedDeserializers;
4546

4647
/**
4748
* During deserializer construction process we may need to keep track of partially

src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.fasterxml.jackson.databind.cfg.MapperConfig;
1212
import com.fasterxml.jackson.databind.type.SimpleType;
1313
import com.fasterxml.jackson.databind.util.ClassUtil;
14+
import com.fasterxml.jackson.databind.util.LookupCache;
1415
import com.fasterxml.jackson.databind.util.SimpleLookupCache;
1516

1617
public class BasicClassIntrospector
@@ -60,13 +61,13 @@ public class BasicClassIntrospector
6061
* because {@link #forMapper(Object)} initializes it properly, when mapper get
6162
* constructed.
6263
*/
63-
protected final transient SimpleLookupCache<JavaType,BasicBeanDescription> _cachedFCA;
64+
protected final transient LookupCache<JavaType,BasicBeanDescription> _cachedFCA;
6465

6566
public BasicClassIntrospector() {
6667
this(null);
6768
}
6869

69-
protected BasicClassIntrospector(SimpleLookupCache<JavaType,BasicBeanDescription> cache) {
70+
protected BasicClassIntrospector(LookupCache<JavaType,BasicBeanDescription> cache) {
7071
_cachedFCA = cache;
7172
}
7273

src/main/java/com/fasterxml/jackson/databind/introspect/JacksonAnnotationIntrospector.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public class JacksonAnnotationIntrospector
7878
*<p>
7979
* Non-final only because it needs to be re-created after deserialization.
8080
*/
81-
protected transient SimpleLookupCache<Class<?>,Boolean> _annotationsInside = new SimpleLookupCache<Class<?>,Boolean>(48, 96);
81+
protected transient LookupCache<Class<?>,Boolean> _annotationsInside = new SimpleLookupCache<Class<?>,Boolean>(48, 96);
8282

8383
/*
8484
/**********************************************************************

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public SerializerCache(int maxCached) {
6060
_readOnlyMap = new AtomicReference<ReadOnlyClassToSerializerMap>();
6161
}
6262

63-
private SerializerCache(SimpleLookupCache<TypeKey, JsonSerializer<Object>> shared) {
63+
protected SerializerCache(SimpleLookupCache<TypeKey, JsonSerializer<Object>> shared) {
6464
_sharedMap = shared;
6565
_readOnlyMap = new AtomicReference<ReadOnlyClassToSerializerMap>();
6666
}

src/main/java/com/fasterxml/jackson/databind/type/TypeFactory.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.databind.JsonNode;
1111
import com.fasterxml.jackson.databind.util.ArrayBuilders;
1212
import com.fasterxml.jackson.databind.util.ClassUtil;
13+
import com.fasterxml.jackson.databind.util.LookupCache;
1314
import com.fasterxml.jackson.databind.util.SimpleLookupCache;
1415

1516
/**
@@ -121,7 +122,7 @@ public final class TypeFactory
121122
* actual generic types), we will use small cache to avoid repetitive
122123
* resolution of core types
123124
*/
124-
protected final SimpleLookupCache<Object,JavaType> _typeCache;
125+
protected final LookupCache<Object,JavaType> _typeCache;
125126

126127
/*
127128
/**********************************************************************
@@ -150,7 +151,7 @@ private TypeFactory() {
150151
this(null);
151152
}
152153

153-
protected TypeFactory(SimpleLookupCache<Object,JavaType> typeCache) {
154+
protected TypeFactory(LookupCache<Object,JavaType> typeCache) {
154155
if (typeCache == null) {
155156
typeCache = new SimpleLookupCache<Object,JavaType>(16, 200);
156157
}
@@ -159,7 +160,7 @@ protected TypeFactory(SimpleLookupCache<Object,JavaType> typeCache) {
159160
_classLoader = null;
160161
}
161162

162-
protected TypeFactory(SimpleLookupCache<Object,JavaType> typeCache,
163+
protected TypeFactory(LookupCache<Object,JavaType> typeCache,
163164
TypeModifier[] mods, ClassLoader classLoader)
164165
{
165166
if (typeCache == null) {
@@ -190,7 +191,7 @@ public TypeFactory snapshot() {
190191
*/
191192
public TypeFactory withModifier(TypeModifier mod)
192193
{
193-
SimpleLookupCache<Object,JavaType> typeCache = _typeCache;
194+
LookupCache<Object,JavaType> typeCache = _typeCache;
194195
TypeModifier[] mods;
195196
if (mod == null) { // mostly for unit tests
196197
mods = null;
@@ -222,7 +223,7 @@ public TypeFactory withClassLoader(ClassLoader classLoader) {
222223
* identical settings except for different cache; most likely one with
223224
* bigger maximum size.
224225
*/
225-
public TypeFactory withCache(SimpleLookupCache<Object,JavaType> cache) {
226+
public TypeFactory withCache(LookupCache<Object,JavaType> cache) {
226227
return new TypeFactory(cache, _modifiers, _classLoader);
227228
}
228229

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.fasterxml.jackson.databind.util;
2+
3+
import com.fasterxml.jackson.core.util.Snapshottable;
4+
5+
/**
6+
* An interface describing the required API for the Jackson-Databind Type cache.
7+
*<p>
8+
* Note that while interface itself does not specify synchronization requirements for
9+
* implementations, specific use cases do. Typically implementations are
10+
* expected to be thread-safe, that is, to handle synchronization.
11+
*
12+
* @see com.fasterxml.jackson.databind.type.TypeFactory#withCache(LookupCache<java.lang.Object,com.fasterxml.jackson.databind.JavaType>)
13+
* @see SimpleLookupCache
14+
*/
15+
public interface LookupCache <K,V>
16+
extends Snapshottable<LookupCache<K,V>>
17+
{
18+
// 17-Sep-2019, tatu: There is one usage, by `ReadOnlyClassToSerializerMap`, so
19+
// for now NOT exposed, but can reconsider if it proves generally useful
20+
21+
// void contents(BiConsumer<K,V> consumer);
22+
23+
/**
24+
* @return Number of entries currently in cache: may be approximate, only
25+
* to be used for diagnostics, metrics reporting
26+
*/
27+
int size();
28+
29+
/**
30+
* NOTE: key is of type Object only to retain binary backwards-compatibility
31+
*
32+
* @param key
33+
* @return value associated with key (can return null)
34+
*/
35+
V get(Object key);
36+
37+
V put(K key, V value);
38+
39+
V putIfAbsent(K key, V value);
40+
41+
/**
42+
* Method for removing all contents this cache has.
43+
*/
44+
void clear();
45+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class RootNameLookup implements java.io.Serializable
1616
* For efficient operation, let's try to minimize number of times we
1717
* need to introspect root element name to use.
1818
*/
19-
protected transient SimpleLookupCache<ClassKey,PropertyName> _rootNames;
19+
protected transient LookupCache<ClassKey,PropertyName> _rootNames;
2020

2121
public RootNameLookup() {
2222
_rootNames = new SimpleLookupCache<ClassKey,PropertyName>(20, 200);

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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import java.util.concurrent.ConcurrentHashMap;
55
import java.util.function.BiConsumer;
66

7-
import com.fasterxml.jackson.core.util.Snapshottable;
8-
97
/**
108
* Synchronized cache with bounded size: used for reusing lookup values
119
* and lazily instantiated reusable items.
@@ -26,8 +24,7 @@
2624
* a shaded variant may be used one day.
2725
*/
2826
public class SimpleLookupCache<K,V>
29-
implements Snapshottable<SimpleLookupCache<K,V>>,
30-
java.io.Serializable
27+
implements LookupCache<K,V>, java.io.Serializable
3128
{
3229
private static final long serialVersionUID = 3L;
3330

@@ -55,22 +52,17 @@ protected Object readResolve() {
5552
}
5653

5754
@Override
58-
public SimpleLookupCache<K, V> snapshot() {
55+
public SimpleLookupCache<K,V> snapshot() {
5956
return new SimpleLookupCache<K,V>(_initialEntries, _maxEntries);
6057
}
6158

62-
public void contents(BiConsumer<K,V> consumer) {
63-
for (Map.Entry<K,V> entry : _map.entrySet()) {
64-
consumer.accept(entry.getKey(), entry.getValue());
65-
}
66-
}
67-
6859
/*
6960
/**********************************************************************
70-
/* Public API
61+
/* Public API, basic lookup/additions
7162
/**********************************************************************
7263
*/
7364

65+
@Override
7466
public V put(K key, V value) {
7567
if (_map.size() >= _maxEntries) {
7668
// double-locking, yes, but safe here; trying to avoid "clear storms"
@@ -83,6 +75,7 @@ public V put(K key, V value) {
8375
return _map.put(key, value);
8476
}
8577

78+
@Override
8679
public V putIfAbsent(K key, V value) {
8780
// not 100% optimal semantically, but better from correctness (never exceeds
8881
// defined maximum) and close enough all in all:
@@ -96,9 +89,24 @@ public V putIfAbsent(K key, V value) {
9689
return _map.putIfAbsent(key, value);
9790
}
9891

99-
// NOTE: key is of type Object only to retain binary backwards-compatibility
92+
@Override
10093
public V get(Object key) { return _map.get(key); }
10194

95+
@Override
10296
public void clear() { _map.clear(); }
97+
98+
@Override
10399
public int size() { return _map.size(); }
100+
101+
/*
102+
/**********************************************************************
103+
/* Extended API
104+
/**********************************************************************
105+
*/
106+
107+
public void contents(BiConsumer<K,V> consumer) {
108+
for (Map.Entry<K,V> entry : _map.entrySet()) {
109+
consumer.accept(entry.getKey(), entry.getValue());
110+
}
111+
}
104112
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.fasterxml.jackson.databind.util;
2+
3+
import java.util.concurrent.ConcurrentHashMap;
4+
5+
/**
6+
* A LookupCache implementation that has no synchronization (like SimpleLookupCache does)
7+
* but that has the downside of not limiting the size of the cache.
8+
*/
9+
public class UnlimitedLookupCache<K,V> implements LookupCache<K,V> {
10+
11+
private final int _initialEntries, _maxEntries;
12+
private final transient ConcurrentHashMap<K,V> _map;
13+
14+
public UnlimitedLookupCache(int initialEntries, int maxEntries)
15+
{
16+
_initialEntries = initialEntries;
17+
_maxEntries = maxEntries;
18+
// We'll use concurrency level of 4, seems reasonable
19+
_map = new ConcurrentHashMap<K,V>(initialEntries, 0.8f, 4);
20+
}
21+
22+
@Override
23+
public LookupCache<K, V> snapshot() {
24+
return new UnlimitedLookupCache<K,V>(_initialEntries, _maxEntries);
25+
}
26+
27+
/*
28+
@Override
29+
public void contents(BiConsumer<K, V> consumer) {
30+
for (Map.Entry<K,V> entry : _map.entrySet()) {
31+
consumer.accept(entry.getKey(), entry.getValue());
32+
}
33+
}
34+
*/
35+
36+
@Override
37+
public int size() {
38+
return _map.size();
39+
}
40+
41+
@Override
42+
public V get(Object key) {
43+
return _map.get(key);
44+
}
45+
46+
@Override
47+
public V put(K key, V value) {
48+
return _map.put(key, value);
49+
}
50+
51+
@Override
52+
public V putIfAbsent(K key, V value) {
53+
return _map.putIfAbsent(key, value);
54+
}
55+
56+
@Override
57+
public void clear() {
58+
_map.clear();
59+
}
60+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.fasterxml.jackson.databind.util;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.JavaType;
5+
import com.fasterxml.jackson.databind.type.TypeFactory;
6+
import org.junit.Test;
7+
8+
import static org.junit.Assert.assertEquals;
9+
import static org.junit.Assert.assertNotNull;
10+
import static org.junit.Assert.assertNull;
11+
12+
public class UnlimitedLookupCacheTest {
13+
@Test
14+
public void testCache() {
15+
UnlimitedLookupCache<Long, String> cache = new UnlimitedLookupCache<>(4, 10);
16+
assertNull(cache.get(1000L));
17+
assertNull(cache.put(1000L, "Thousand"));
18+
assertEquals("Thousand", cache.get(1000L));
19+
assertEquals("Thousand", cache.putIfAbsent(1000L, "Míle"));
20+
assertEquals("Thousand", cache.get(1000L));
21+
assertEquals("Thousand", cache.put(1000L, "Míle"));
22+
assertEquals("Míle", cache.get(1000L));
23+
cache.clear();
24+
assertNull(cache.put(1000L, "Thousand"));
25+
}
26+
27+
@Test
28+
public void testCompatibility() throws JsonProcessingException {
29+
UnlimitedLookupCache<Object, JavaType> cache = new UnlimitedLookupCache<>(4, 10);
30+
TypeFactory tf = TypeFactory.defaultInstance().withCache(cache);
31+
assertNotNull(tf); // just to get rid of warning
32+
33+
//TODO find way to inject the `tf` instance into an ObjectMapper (via MapperBuilder?)
34+
35+
//ObjectMapper mapper = new ObjectMapper();
36+
//mapper.setTypeFactory(tf);
37+
//assertEquals("1000", mapper.writeValueAsString(1000));
38+
}
39+
}

0 commit comments

Comments
 (0)