Skip to content

Commit b1f4e3c

Browse files
authored
Simplify CodecCache (#1018)
JAVA-4751
1 parent 6068e87 commit b1f4e3c

File tree

4 files changed

+41
-47
lines changed

4 files changed

+41
-47
lines changed

bson/src/main/org/bson/internal/CodecCache.java

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.bson.internal;
1818

1919
import org.bson.codecs.Codec;
20-
import org.bson.codecs.configuration.CodecConfigurationException;
2120

2221
import java.lang.reflect.Type;
2322
import java.util.List;
@@ -26,7 +25,7 @@
2625
import java.util.concurrent.ConcurrentHashMap;
2726
import java.util.concurrent.ConcurrentMap;
2827

29-
import static java.lang.String.format;
28+
import static org.bson.assertions.Assertions.assertNotNull;
3029

3130
final class CodecCache {
3231

@@ -65,29 +64,18 @@ public String toString() {
6564
}
6665
}
6766

68-
private final ConcurrentMap<CodecCacheKey, Optional<Codec<?>>> codecCache = new ConcurrentHashMap<>();
67+
private final ConcurrentMap<CodecCacheKey, Codec<?>> codecCache = new ConcurrentHashMap<>();
6968

70-
public boolean containsKey(final CodecCacheKey codecCacheKey) {
71-
return codecCache.containsKey(codecCacheKey);
69+
public <T> Codec<T> putIfAbsent(final CodecCacheKey codecCacheKey, final Codec<T> codec) {
70+
assertNotNull(codec);
71+
@SuppressWarnings("unchecked")
72+
Codec<T> prevCodec = (Codec<T>) codecCache.putIfAbsent(codecCacheKey, codec);
73+
return prevCodec == null ? codec : prevCodec;
7274
}
7375

74-
public void put(final CodecCacheKey codecCacheKey, final Codec<?> codec){
75-
codecCache.put(codecCacheKey, Optional.ofNullable(codec));
76-
}
77-
78-
@SuppressWarnings("unchecked")
79-
public synchronized <T> Codec<T> putIfMissing(final CodecCacheKey codecCacheKey, final Codec<T> codec) {
80-
Optional<Codec<?>> cachedCodec = codecCache.computeIfAbsent(codecCacheKey, clz -> Optional.of(codec));
81-
if (cachedCodec.isPresent()) {
82-
return (Codec<T>) cachedCodec.get();
83-
}
84-
codecCache.put(codecCacheKey, Optional.of(codec));
85-
return codec;
86-
}
87-
88-
@SuppressWarnings("unchecked")
89-
public <T> Codec<T> getOrThrow(final CodecCacheKey codecCacheKey) {
90-
return (Codec<T>) codecCache.getOrDefault(codecCacheKey, Optional.empty()).orElseThrow(
91-
() -> new CodecConfigurationException(format("Can't find a codec for %s.", codecCacheKey)));
76+
public <T> Optional<Codec<T>> get(final CodecCacheKey codecCacheKey) {
77+
@SuppressWarnings("unchecked")
78+
Codec<T> codec = (Codec<T>) codecCache.get(codecCacheKey);
79+
return Optional.ofNullable(codec);
9280
}
9381
}

bson/src/main/org/bson/internal/ProvidersCodecRegistry.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import org.bson.codecs.Codec;
2020
import org.bson.codecs.Parameterizable;
21+
import org.bson.codecs.configuration.CodecConfigurationException;
2122
import org.bson.codecs.configuration.CodecProvider;
2223
import org.bson.codecs.configuration.CodecRegistry;
2324
import org.bson.internal.CodecCache.CodecCacheKey;
@@ -67,19 +68,18 @@ public <T> Codec<T> get(final Class<T> clazz, final CodecRegistry registry) {
6768
@SuppressWarnings({"unchecked"})
6869
public <T> Codec<T> get(final ChildCodecRegistry<T> context) {
6970
CodecCacheKey codecCacheKey = new CodecCacheKey(context.getCodecClass(), context.getTypes().orElse(null));
70-
if (!codecCache.containsKey(codecCacheKey)) {
71+
return codecCache.<T>get(codecCacheKey).orElseGet(() -> {
7172
for (CodecProvider provider : codecProviders) {
7273
Codec<T> codec = provider.get(context.getCodecClass(), context);
7374
if (codec != null) {
7475
if (codec instanceof Parameterizable && context.getTypes().isPresent()) {
7576
codec = (Codec<T>) ((Parameterizable) codec).parameterize(context, context.getTypes().get());
7677
}
77-
return codecCache.putIfMissing(codecCacheKey, codec);
78+
return codecCache.putIfAbsent(codecCacheKey, codec);
7879
}
7980
}
80-
codecCache.put(codecCacheKey, null);
81-
}
82-
return codecCache.getOrThrow(codecCacheKey);
81+
throw new CodecConfigurationException(format("Can't find a codec for %s.", codecCacheKey));
82+
});
8383
}
8484

8585
@Override

bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
package org.bson.internal
1818

1919
import org.bson.codecs.MinKeyCodec
20-
import org.bson.codecs.configuration.CodecConfigurationException
2120
import org.bson.types.MinKey
2221
import spock.lang.Specification
2322

@@ -28,40 +27,38 @@ class CodecCacheSpecification extends Specification {
2827
def codec = new MinKeyCodec()
2928
def cache = new CodecCache()
3029
def cacheKey = new CodecCache.CodecCacheKey(MinKey, null)
31-
cache.put(cacheKey, codec)
30+
cache.putIfAbsent(cacheKey, codec)
3231

3332
then:
34-
cache.getOrThrow(cacheKey).is(codec)
33+
cache.get(cacheKey).get().is(codec)
3534
}
3635

37-
def 'should throw if codec for class does not exist'() {
36+
def 'should return empty if codec for class does not exist'() {
3837
when:
3938
def cache = new CodecCache()
4039
def cacheKey = new CodecCache.CodecCacheKey(MinKey, null)
41-
cache.getOrThrow(cacheKey)
4240

4341
then:
44-
thrown(CodecConfigurationException)
42+
!cache.get(cacheKey).isPresent()
4543
}
4644

4745
def 'should return the cached codec if a codec for the parameterized class exists'() {
4846
when:
4947
def codec = new MinKeyCodec()
5048
def cache = new CodecCache()
5149
def cacheKey = new CodecCache.CodecCacheKey(List, [Integer])
52-
cache.put(cacheKey, codec)
50+
cache.putIfAbsent(cacheKey, codec)
5351

5452
then:
55-
cache.getOrThrow(cacheKey).is(codec)
53+
cache.get(cacheKey).get().is(codec)
5654
}
5755

58-
def 'should throw if codec for the parameterized class does not exist'() {
56+
def 'should return empty if codec for the parameterized class does not exist'() {
5957
when:
6058
def cache = new CodecCache()
6159
def cacheKey = new CodecCache.CodecCacheKey(List, [Integer])
62-
cache.getOrThrow(cacheKey)
6360

6461
then:
65-
thrown(CodecConfigurationException)
62+
!cache.get(cacheKey).isPresent()
6663
}
6764
}

bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,22 +115,32 @@ class ProvidersCodecRegistrySpecification extends Specification {
115115

116116
def 'get should use the codecCache'() {
117117
given:
118-
def provider = Mock(CodecProvider)
118+
def codec = Mock(Codec)
119+
def provider = new CodecProvider() {
120+
private int counter = 0
121+
122+
@Override
123+
Codec get(final Class clazz, final CodecRegistry registry) {
124+
if (counter == 0) {
125+
counter++
126+
return codec
127+
}
128+
throw new AssertionError((Object)'Must not be called more than once.')
129+
}
130+
}
119131

120132
when:
121133
def registry = new ProvidersCodecRegistry([provider])
122-
registry.get(MinKey)
134+
def codecFromRegistry = registry.get(MinKey)
123135

124136
then:
125-
thrown(CodecConfigurationException)
126-
1 * provider.get(MinKey, _)
137+
codecFromRegistry == codec
127138

128139
when:
129-
registry.get(MinKey)
140+
codecFromRegistry = registry.get(MinKey)
130141

131142
then:
132-
thrown(CodecConfigurationException)
133-
0 * provider.get(MinKey, _)
143+
codecFromRegistry == codec
134144
}
135145

136146
def 'get with codec registry should return the codec from the first source that has one'() {
@@ -537,4 +547,3 @@ class Nested {
537547
class Simple {
538548
int value = 0
539549
}
540-

0 commit comments

Comments
 (0)