From b2ec80af7d3bb6ead62b002fb431451f8e9c659a Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Mon, 17 Oct 2022 16:58:35 -0600 Subject: [PATCH 1/5] Simplify CodecCache JAVA-4751 --- .../main/org/bson/internal/CodecCache.java | 34 ++++++------------- .../bson/internal/ProvidersCodecRegistry.java | 10 +++--- .../internal/CodecCacheSpecification.groovy | 19 +++++------ 3 files changed, 24 insertions(+), 39 deletions(-) diff --git a/bson/src/main/org/bson/internal/CodecCache.java b/bson/src/main/org/bson/internal/CodecCache.java index c4b59d713b4..bec178559e3 100644 --- a/bson/src/main/org/bson/internal/CodecCache.java +++ b/bson/src/main/org/bson/internal/CodecCache.java @@ -17,7 +17,6 @@ package org.bson.internal; import org.bson.codecs.Codec; -import org.bson.codecs.configuration.CodecConfigurationException; import java.lang.reflect.Type; import java.util.List; @@ -26,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import static java.lang.String.format; +import static org.bson.assertions.Assertions.assertNotNull; final class CodecCache { @@ -65,29 +64,18 @@ public String toString() { } } - private final ConcurrentMap>> codecCache = new ConcurrentHashMap<>(); + private final ConcurrentMap> codecCache = new ConcurrentHashMap<>(); - public boolean containsKey(final CodecCacheKey codecCacheKey) { - return codecCache.containsKey(codecCacheKey); + public Codec putIfAbsent(final CodecCacheKey codecCacheKey, final Codec codec) { + assertNotNull(codec); + @SuppressWarnings("unchecked") + Codec prevCodec = (Codec) codecCache.putIfAbsent(codecCacheKey, codec); + return prevCodec == null ? codec : prevCodec; } - public void put(final CodecCacheKey codecCacheKey, final Codec codec){ - codecCache.put(codecCacheKey, Optional.ofNullable(codec)); - } - - @SuppressWarnings("unchecked") - public synchronized Codec putIfMissing(final CodecCacheKey codecCacheKey, final Codec codec) { - Optional> cachedCodec = codecCache.computeIfAbsent(codecCacheKey, clz -> Optional.of(codec)); - if (cachedCodec.isPresent()) { - return (Codec) cachedCodec.get(); - } - codecCache.put(codecCacheKey, Optional.of(codec)); - return codec; - } - - @SuppressWarnings("unchecked") - public Codec getOrThrow(final CodecCacheKey codecCacheKey) { - return (Codec) codecCache.getOrDefault(codecCacheKey, Optional.empty()).orElseThrow( - () -> new CodecConfigurationException(format("Can't find a codec for %s.", codecCacheKey))); + public Optional> get(final CodecCacheKey codecCacheKey) { + @SuppressWarnings("unchecked") + Codec codec = (Codec) codecCache.get(codecCacheKey); + return Optional.ofNullable(codec); } } diff --git a/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java b/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java index 8f6d4f0d7c3..6e8708f66ab 100644 --- a/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java +++ b/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java @@ -18,6 +18,7 @@ import org.bson.codecs.Codec; import org.bson.codecs.Parameterizable; +import org.bson.codecs.configuration.CodecConfigurationException; import org.bson.codecs.configuration.CodecProvider; import org.bson.codecs.configuration.CodecRegistry; import org.bson.internal.CodecCache.CodecCacheKey; @@ -67,19 +68,18 @@ public Codec get(final Class clazz, final CodecRegistry registry) { @SuppressWarnings({"unchecked"}) public Codec get(final ChildCodecRegistry context) { CodecCacheKey codecCacheKey = new CodecCacheKey(context.getCodecClass(), context.getTypes().orElse(null)); - if (!codecCache.containsKey(codecCacheKey)) { + return codecCache.get(codecCacheKey).orElseGet(() -> { for (CodecProvider provider : codecProviders) { Codec codec = provider.get(context.getCodecClass(), context); if (codec != null) { if (codec instanceof Parameterizable && context.getTypes().isPresent()) { codec = (Codec) ((Parameterizable) codec).parameterize(context, context.getTypes().get()); } - return codecCache.putIfMissing(codecCacheKey, codec); + return codecCache.putIfAbsent(codecCacheKey, codec); } } - codecCache.put(codecCacheKey, null); - } - return codecCache.getOrThrow(codecCacheKey); + throw new CodecConfigurationException(format("Can't find a codec for %s.", codecCacheKey)); + }); } @Override diff --git a/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy b/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy index 5d34d29ff2e..09b40735f1f 100644 --- a/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy +++ b/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy @@ -17,7 +17,6 @@ package org.bson.internal import org.bson.codecs.MinKeyCodec -import org.bson.codecs.configuration.CodecConfigurationException import org.bson.types.MinKey import spock.lang.Specification @@ -28,20 +27,19 @@ class CodecCacheSpecification extends Specification { def codec = new MinKeyCodec() def cache = new CodecCache() def cacheKey = new CodecCache.CodecCacheKey(MinKey, null) - cache.put(cacheKey, codec) + cache.putIfAbsent(cacheKey, codec) then: - cache.getOrThrow(cacheKey).is(codec) + cache.get(cacheKey).get().is(codec) } - def 'should throw if codec for class does not exist'() { + def 'should return empty if codec for class does not exist'() { when: def cache = new CodecCache() def cacheKey = new CodecCache.CodecCacheKey(MinKey, null) - cache.getOrThrow(cacheKey) then: - thrown(CodecConfigurationException) + !cache.get(cacheKey).isPresent() } def 'should return the cached codec if a codec for the parameterized class exists'() { @@ -49,19 +47,18 @@ class CodecCacheSpecification extends Specification { def codec = new MinKeyCodec() def cache = new CodecCache() def cacheKey = new CodecCache.CodecCacheKey(List, [Integer]) - cache.put(cacheKey, codec) + cache.putIfAbsent(cacheKey, codec) then: - cache.getOrThrow(cacheKey).is(codec) + cache.get(cacheKey).get().is(codec) } - def 'should throw if codec for the parameterized class does not exist'() { + def 'should return empty if codec for the parameterized class does not exist'() { when: def cache = new CodecCache() def cacheKey = new CodecCache.CodecCacheKey(List, [Integer]) - cache.getOrThrow(cacheKey) then: - thrown(CodecConfigurationException) + !cache.get(cacheKey).isPresent() } } From 35ccec5f7cce64c3e6c6d58d7bc7ca302a46eb72 Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Mon, 17 Oct 2022 20:29:25 -0600 Subject: [PATCH 2/5] Fix the failing test JAVA-4751 --- ...ProvidersCodecRegistrySpecification.groovy | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy b/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy index efc64f80a67..3d37522f68c 100644 --- a/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy +++ b/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy @@ -115,22 +115,34 @@ class ProvidersCodecRegistrySpecification extends Specification { def 'get should use the codecCache'() { given: - def provider = Mock(CodecProvider) + def codec = Mock(Codec) + def provider = new CodecProvider() { + private int counter = 0 + + @Override + Codec get(final Class clazz, final CodecRegistry registry) { + if (counter == 0) { + counter++ + return codec + } else { + throw new AssertionError((Object)"Must not be called more than once.") + } + + } + } when: def registry = new ProvidersCodecRegistry([provider]) - registry.get(MinKey) + def codecFromRegistry = registry.get(MinKey) then: - thrown(CodecConfigurationException) - 1 * provider.get(MinKey, _) + codecFromRegistry == codec when: - registry.get(MinKey) + codecFromRegistry = registry.get(MinKey) then: - thrown(CodecConfigurationException) - 0 * provider.get(MinKey, _) + codecFromRegistry == codec } def 'get with codec registry should return the codec from the first source that has one'() { @@ -537,4 +549,3 @@ class Nested { class Simple { int value = 0 } - From c4f2ff6b2ddd05c70ff52999ba72e4a1fe337d2c Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Mon, 17 Oct 2022 20:38:38 -0600 Subject: [PATCH 3/5] Fix the failing test JAVA-4751 --- .../bson/internal/ProvidersCodecRegistrySpecification.groovy | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy b/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy index 3d37522f68c..4819f2ed50a 100644 --- a/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy +++ b/bson/src/test/unit/org/bson/internal/ProvidersCodecRegistrySpecification.groovy @@ -124,10 +124,8 @@ class ProvidersCodecRegistrySpecification extends Specification { if (counter == 0) { counter++ return codec - } else { - throw new AssertionError((Object)"Must not be called more than once.") } - + throw new AssertionError((Object)'Must not be called more than once.') } } From 12528a818a49aaa12f5f522e59ccfd93c959de26 Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Tue, 18 Oct 2022 09:01:09 -0600 Subject: [PATCH 4/5] Cut more wobbling code down JAVA-4751 --- .../main/org/bson/internal/CodecCache.java | 81 ------------------- .../bson/internal/ProvidersCodecRegistry.java | 51 ++++++++++-- .../internal/CodecCacheSpecification.groovy | 64 --------------- 3 files changed, 44 insertions(+), 152 deletions(-) delete mode 100644 bson/src/main/org/bson/internal/CodecCache.java delete mode 100644 bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy diff --git a/bson/src/main/org/bson/internal/CodecCache.java b/bson/src/main/org/bson/internal/CodecCache.java deleted file mode 100644 index bec178559e3..00000000000 --- a/bson/src/main/org/bson/internal/CodecCache.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2008-present MongoDB, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.bson.internal; - -import org.bson.codecs.Codec; - -import java.lang.reflect.Type; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import static org.bson.assertions.Assertions.assertNotNull; - -final class CodecCache { - - static final class CodecCacheKey { - private final Class clazz; - private final List types; - - CodecCacheKey(final Class clazz, final List types) { - this.clazz = clazz; - this.types = types; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CodecCacheKey that = (CodecCacheKey) o; - return clazz.equals(that.clazz) && Objects.equals(types, that.types); - } - - @Override - public int hashCode() { - return Objects.hash(clazz, types); - } - - @Override - public String toString() { - return "CodecCacheKey{" - + "clazz=" + clazz - + ", types=" + types - + '}'; - } - } - - private final ConcurrentMap> codecCache = new ConcurrentHashMap<>(); - - public Codec putIfAbsent(final CodecCacheKey codecCacheKey, final Codec codec) { - assertNotNull(codec); - @SuppressWarnings("unchecked") - Codec prevCodec = (Codec) codecCache.putIfAbsent(codecCacheKey, codec); - return prevCodec == null ? codec : prevCodec; - } - - public Optional> get(final CodecCacheKey codecCacheKey) { - @SuppressWarnings("unchecked") - Codec codec = (Codec) codecCache.get(codecCacheKey); - return Optional.ofNullable(codec); - } -} diff --git a/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java b/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java index 6e8708f66ab..2c11f6a1e3a 100644 --- a/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java +++ b/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java @@ -21,11 +21,13 @@ import org.bson.codecs.configuration.CodecConfigurationException; import org.bson.codecs.configuration.CodecProvider; import org.bson.codecs.configuration.CodecRegistry; -import org.bson.internal.CodecCache.CodecCacheKey; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import static java.lang.String.format; import static org.bson.assertions.Assertions.isTrueArgument; @@ -33,7 +35,7 @@ public final class ProvidersCodecRegistry implements CycleDetectingCodecRegistry { private final List codecProviders; - private final CodecCache codecCache = new CodecCache(); + private final ConcurrentMap> codecCache = new ConcurrentHashMap<>(); public ProvidersCodecRegistry(final List codecProviders) { isTrueArgument("codecProviders must not be null or empty", codecProviders != null && codecProviders.size() > 0); @@ -68,17 +70,17 @@ public Codec get(final Class clazz, final CodecRegistry registry) { @SuppressWarnings({"unchecked"}) public Codec get(final ChildCodecRegistry context) { CodecCacheKey codecCacheKey = new CodecCacheKey(context.getCodecClass(), context.getTypes().orElse(null)); - return codecCache.get(codecCacheKey).orElseGet(() -> { + return (Codec) codecCache.computeIfAbsent(codecCacheKey, k -> { for (CodecProvider provider : codecProviders) { - Codec codec = provider.get(context.getCodecClass(), context); + Codec codec = provider.get(context.getCodecClass(), context); if (codec != null) { if (codec instanceof Parameterizable && context.getTypes().isPresent()) { - codec = (Codec) ((Parameterizable) codec).parameterize(context, context.getTypes().get()); + codec = ((Parameterizable) codec).parameterize(context, context.getTypes().get()); } - return codecCache.putIfAbsent(codecCacheKey, codec); + return codec; } } - throw new CodecConfigurationException(format("Can't find a codec for %s.", codecCacheKey)); + throw new CodecConfigurationException(format("Can't find a codec for %s.", k)); }); } @@ -114,4 +116,39 @@ public String toString() { + "codecProviders=" + codecProviders + '}'; } + + private static final class CodecCacheKey { + private final Class clazz; + private final List types; + + CodecCacheKey(final Class clazz, final List types) { + this.clazz = clazz; + this.types = types; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CodecCacheKey that = (CodecCacheKey) o; + return clazz.equals(that.clazz) && Objects.equals(types, that.types); + } + + @Override + public int hashCode() { + return Objects.hash(clazz, types); + } + + @Override + public String toString() { + return "CodecCacheKey{" + + "clazz=" + clazz + + ", types=" + types + + '}'; + } + } } diff --git a/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy b/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy deleted file mode 100644 index 09b40735f1f..00000000000 --- a/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2008-present MongoDB, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.bson.internal - -import org.bson.codecs.MinKeyCodec -import org.bson.types.MinKey -import spock.lang.Specification - -class CodecCacheSpecification extends Specification { - - def 'should return the cached codec if a codec for the class exists'() { - when: - def codec = new MinKeyCodec() - def cache = new CodecCache() - def cacheKey = new CodecCache.CodecCacheKey(MinKey, null) - cache.putIfAbsent(cacheKey, codec) - - then: - cache.get(cacheKey).get().is(codec) - } - - def 'should return empty if codec for class does not exist'() { - when: - def cache = new CodecCache() - def cacheKey = new CodecCache.CodecCacheKey(MinKey, null) - - then: - !cache.get(cacheKey).isPresent() - } - - def 'should return the cached codec if a codec for the parameterized class exists'() { - when: - def codec = new MinKeyCodec() - def cache = new CodecCache() - def cacheKey = new CodecCache.CodecCacheKey(List, [Integer]) - cache.putIfAbsent(cacheKey, codec) - - then: - cache.get(cacheKey).get().is(codec) - } - - def 'should return empty if codec for the parameterized class does not exist'() { - when: - def cache = new CodecCache() - def cacheKey = new CodecCache.CodecCacheKey(List, [Integer]) - - then: - !cache.get(cacheKey).isPresent() - } -} From 0ff97595d2dca339fe17b854307c4777415fca4e Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Tue, 18 Oct 2022 09:21:22 -0600 Subject: [PATCH 5/5] Revert "Cut more wobbling code down" This reverts commit 12528a818a49aaa12f5f522e59ccfd93c959de26. --- .../main/org/bson/internal/CodecCache.java | 81 +++++++++++++++++++ .../bson/internal/ProvidersCodecRegistry.java | 51 ++---------- .../internal/CodecCacheSpecification.groovy | 64 +++++++++++++++ 3 files changed, 152 insertions(+), 44 deletions(-) create mode 100644 bson/src/main/org/bson/internal/CodecCache.java create mode 100644 bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy diff --git a/bson/src/main/org/bson/internal/CodecCache.java b/bson/src/main/org/bson/internal/CodecCache.java new file mode 100644 index 00000000000..bec178559e3 --- /dev/null +++ b/bson/src/main/org/bson/internal/CodecCache.java @@ -0,0 +1,81 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bson.internal; + +import org.bson.codecs.Codec; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static org.bson.assertions.Assertions.assertNotNull; + +final class CodecCache { + + static final class CodecCacheKey { + private final Class clazz; + private final List types; + + CodecCacheKey(final Class clazz, final List types) { + this.clazz = clazz; + this.types = types; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CodecCacheKey that = (CodecCacheKey) o; + return clazz.equals(that.clazz) && Objects.equals(types, that.types); + } + + @Override + public int hashCode() { + return Objects.hash(clazz, types); + } + + @Override + public String toString() { + return "CodecCacheKey{" + + "clazz=" + clazz + + ", types=" + types + + '}'; + } + } + + private final ConcurrentMap> codecCache = new ConcurrentHashMap<>(); + + public Codec putIfAbsent(final CodecCacheKey codecCacheKey, final Codec codec) { + assertNotNull(codec); + @SuppressWarnings("unchecked") + Codec prevCodec = (Codec) codecCache.putIfAbsent(codecCacheKey, codec); + return prevCodec == null ? codec : prevCodec; + } + + public Optional> get(final CodecCacheKey codecCacheKey) { + @SuppressWarnings("unchecked") + Codec codec = (Codec) codecCache.get(codecCacheKey); + return Optional.ofNullable(codec); + } +} diff --git a/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java b/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java index 2c11f6a1e3a..6e8708f66ab 100644 --- a/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java +++ b/bson/src/main/org/bson/internal/ProvidersCodecRegistry.java @@ -21,13 +21,11 @@ import org.bson.codecs.configuration.CodecConfigurationException; import org.bson.codecs.configuration.CodecProvider; import org.bson.codecs.configuration.CodecRegistry; +import org.bson.internal.CodecCache.CodecCacheKey; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import static java.lang.String.format; import static org.bson.assertions.Assertions.isTrueArgument; @@ -35,7 +33,7 @@ public final class ProvidersCodecRegistry implements CycleDetectingCodecRegistry { private final List codecProviders; - private final ConcurrentMap> codecCache = new ConcurrentHashMap<>(); + private final CodecCache codecCache = new CodecCache(); public ProvidersCodecRegistry(final List codecProviders) { isTrueArgument("codecProviders must not be null or empty", codecProviders != null && codecProviders.size() > 0); @@ -70,17 +68,17 @@ public Codec get(final Class clazz, final CodecRegistry registry) { @SuppressWarnings({"unchecked"}) public Codec get(final ChildCodecRegistry context) { CodecCacheKey codecCacheKey = new CodecCacheKey(context.getCodecClass(), context.getTypes().orElse(null)); - return (Codec) codecCache.computeIfAbsent(codecCacheKey, k -> { + return codecCache.get(codecCacheKey).orElseGet(() -> { for (CodecProvider provider : codecProviders) { - Codec codec = provider.get(context.getCodecClass(), context); + Codec codec = provider.get(context.getCodecClass(), context); if (codec != null) { if (codec instanceof Parameterizable && context.getTypes().isPresent()) { - codec = ((Parameterizable) codec).parameterize(context, context.getTypes().get()); + codec = (Codec) ((Parameterizable) codec).parameterize(context, context.getTypes().get()); } - return codec; + return codecCache.putIfAbsent(codecCacheKey, codec); } } - throw new CodecConfigurationException(format("Can't find a codec for %s.", k)); + throw new CodecConfigurationException(format("Can't find a codec for %s.", codecCacheKey)); }); } @@ -116,39 +114,4 @@ public String toString() { + "codecProviders=" + codecProviders + '}'; } - - private static final class CodecCacheKey { - private final Class clazz; - private final List types; - - CodecCacheKey(final Class clazz, final List types) { - this.clazz = clazz; - this.types = types; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CodecCacheKey that = (CodecCacheKey) o; - return clazz.equals(that.clazz) && Objects.equals(types, that.types); - } - - @Override - public int hashCode() { - return Objects.hash(clazz, types); - } - - @Override - public String toString() { - return "CodecCacheKey{" - + "clazz=" + clazz - + ", types=" + types - + '}'; - } - } } diff --git a/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy b/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy new file mode 100644 index 00000000000..09b40735f1f --- /dev/null +++ b/bson/src/test/unit/org/bson/internal/CodecCacheSpecification.groovy @@ -0,0 +1,64 @@ +/* + * Copyright 2008-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bson.internal + +import org.bson.codecs.MinKeyCodec +import org.bson.types.MinKey +import spock.lang.Specification + +class CodecCacheSpecification extends Specification { + + def 'should return the cached codec if a codec for the class exists'() { + when: + def codec = new MinKeyCodec() + def cache = new CodecCache() + def cacheKey = new CodecCache.CodecCacheKey(MinKey, null) + cache.putIfAbsent(cacheKey, codec) + + then: + cache.get(cacheKey).get().is(codec) + } + + def 'should return empty if codec for class does not exist'() { + when: + def cache = new CodecCache() + def cacheKey = new CodecCache.CodecCacheKey(MinKey, null) + + then: + !cache.get(cacheKey).isPresent() + } + + def 'should return the cached codec if a codec for the parameterized class exists'() { + when: + def codec = new MinKeyCodec() + def cache = new CodecCache() + def cacheKey = new CodecCache.CodecCacheKey(List, [Integer]) + cache.putIfAbsent(cacheKey, codec) + + then: + cache.get(cacheKey).get().is(codec) + } + + def 'should return empty if codec for the parameterized class does not exist'() { + when: + def cache = new CodecCache() + def cacheKey = new CodecCache.CodecCacheKey(List, [Integer]) + + then: + !cache.get(cacheKey).isPresent() + } +}