From d439e79691201999fcf0eae98fafc09a7dde021b Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Tue, 7 Feb 2023 12:02:05 -0700 Subject: [PATCH 1/4] Make sure that `BsonDocument.clone` returns a mutable deep copy --- bson/src/main/org/bson/RawBsonDocument.java | 2 +- .../test/unit/org/bson/BsonDocumentTest.java | 33 +++++++++++++++++-- .../bson/RawBsonDocumentSpecification.groovy | 5 ++- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/bson/src/main/org/bson/RawBsonDocument.java b/bson/src/main/org/bson/RawBsonDocument.java index eb672bcef8d..aac8c42b423 100644 --- a/bson/src/main/org/bson/RawBsonDocument.java +++ b/bson/src/main/org/bson/RawBsonDocument.java @@ -328,7 +328,7 @@ public int hashCode() { @Override public BsonDocument clone() { - return new RawBsonDocument(bytes.clone(), offset, length); + return toBaseBsonDocument(); } private BsonBinaryReader createReader() { diff --git a/bson/src/test/unit/org/bson/BsonDocumentTest.java b/bson/src/test/unit/org/bson/BsonDocumentTest.java index 0ec2c007296..a352dab65a4 100644 --- a/bson/src/test/unit/org/bson/BsonDocumentTest.java +++ b/bson/src/test/unit/org/bson/BsonDocumentTest.java @@ -23,13 +23,16 @@ import org.bson.json.JsonReader; import org.bson.json.JsonWriter; import org.bson.json.JsonWriterSettings; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.io.StringWriter; import java.util.Arrays; +import java.util.function.Consumer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; // Don't convert to Spock, as Groovy intercepts equals/hashCode methods that we are trying to test public class BsonDocumentTest { @@ -106,4 +109,28 @@ public void toStringShouldEqualToJson() { public void shouldParseJson() { assertEquals(new BsonDocument("a", new BsonInt32(1)), BsonDocument.parse("{\"a\" : 1}")); } + + @Test + public void cloneIsDeepCopyAndMutable() { + Consumer assertCloneDeepCopyMutable = original -> { + BsonDocument clone = original.clone(); + assertNotSame(original, clone); + assertEquals(original, clone); + // check that mutating `clone` does not mutate `original` + clone.getDocument("k1").put("k2", new BsonString("clone")); + assertEquals(new BsonString("clone"), clone.getDocument("k1").get("k2")); + assertEquals(BsonNull.VALUE, original.getDocument("k1").get("k2")); + // check that mutating `original` (if it is mutable) does not mutate `clone` + if (!(original instanceof RawBsonDocument)) { + original.put("k1", new BsonDocument("k2", new BsonString("original"))); + assertEquals(new BsonString("original"), original.getDocument("k1").get("k2")); + assertEquals(new BsonString("clone"), clone.getDocument("k1").get("k2")); + } + }; + assertAll( + () -> assertCloneDeepCopyMutable.accept(new BsonDocument("k1", new BsonDocument("k2", BsonNull.VALUE))), + () -> assertCloneDeepCopyMutable.accept(new BsonDocument("k1", RawBsonDocument.parse("{'k2': null}"))), + () -> assertCloneDeepCopyMutable.accept(RawBsonDocument.parse("{'k1': {'k2': null}}")) + ); + } } diff --git a/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy b/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy index a23ec06dedb..462d75b2a86 100644 --- a/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy +++ b/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy @@ -395,11 +395,10 @@ class RawBsonDocumentSpecification extends Specification { def 'clone should make a deep copy'() { when: - RawBsonDocument cloned = rawDocument.clone() + BsonDocument cloned = rawDocument.clone() then: - !cloned.getByteBuffer().array().is(createRawDocumenFromDocument().getByteBuffer().array()) - cloned.getByteBuffer().remaining() == rawDocument.getByteBuffer().remaining() + cloned.getClass() == BsonDocument cloned == createRawDocumenFromDocument() where: From a525a649d3c1c189bc0f112210c04fc00bdccde2 Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Thu, 9 Feb 2023 18:31:13 -0700 Subject: [PATCH 2/4] Introduce Util.mutableDeepCopy JAVA-4874 --- bson/src/main/org/bson/RawBsonDocument.java | 2 +- bson/src/main/org/bson/internal/Util.java | 73 ++++++++++ .../test/unit/org/bson/BsonDocumentTest.java | 33 +---- .../bson/RawBsonDocumentSpecification.groovy | 5 +- .../test/unit/org/bson/internal/UtilTest.java | 131 ++++++++++++++++++ .../model/AbstractConstructibleBson.java | 4 +- .../internal/vault/ClientEncryptionImpl.java | 3 +- .../client/internal/ClientEncryptionImpl.java | 3 +- 8 files changed, 218 insertions(+), 36 deletions(-) create mode 100644 bson/src/main/org/bson/internal/Util.java create mode 100644 bson/src/test/unit/org/bson/internal/UtilTest.java diff --git a/bson/src/main/org/bson/RawBsonDocument.java b/bson/src/main/org/bson/RawBsonDocument.java index aac8c42b423..eb672bcef8d 100644 --- a/bson/src/main/org/bson/RawBsonDocument.java +++ b/bson/src/main/org/bson/RawBsonDocument.java @@ -328,7 +328,7 @@ public int hashCode() { @Override public BsonDocument clone() { - return toBaseBsonDocument(); + return new RawBsonDocument(bytes.clone(), offset, length); } private BsonBinaryReader createReader() { diff --git a/bson/src/main/org/bson/internal/Util.java b/bson/src/main/org/bson/internal/Util.java new file mode 100644 index 00000000000..751e703b416 --- /dev/null +++ b/bson/src/main/org/bson/internal/Util.java @@ -0,0 +1,73 @@ +/* + * 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.BsonArray; +import org.bson.BsonBinary; +import org.bson.BsonDocument; +import org.bson.BsonJavaScriptWithScope; +import org.bson.BsonValue; + +/** + *

This class is not part of the public API and may be removed or changed at any time

+ */ +public final class Util { + public static BsonDocument mutableDeepCopy(final BsonDocument original) { + BsonDocument copy = new BsonDocument(original.size()); + original.forEach((key, value) -> copy.put(key, mutableDeepCopy(value))); + return copy; + } + + private static BsonArray mutableDeepCopy(final BsonArray original) { + BsonArray copy = new BsonArray(original.size()); + original.forEach(element -> copy.add(mutableDeepCopy(element))); + return copy; + } + + private static BsonBinary mutableDeepCopy(final BsonBinary original) { + return new BsonBinary(original.getType(), original.getData().clone()); + } + + private static BsonJavaScriptWithScope mutableDeepCopy(final BsonJavaScriptWithScope original) { + return new BsonJavaScriptWithScope(original.getCode(), mutableDeepCopy(original.getScope())); + } + + private static T mutableDeepCopy(final T original) { + BsonValue copy; + switch (original.getBsonType()) { + case DOCUMENT: + copy = mutableDeepCopy(original.asDocument()); + break; + case ARRAY: + copy = mutableDeepCopy(original.asArray()); + break; + case BINARY: + copy = mutableDeepCopy(original.asBinary()); + break; + case JAVASCRIPT_WITH_SCOPE: + copy = mutableDeepCopy(original.asJavaScriptWithScope()); + break; + default: + copy = original; + } + @SuppressWarnings("unchecked") + T result = (T) copy; + return result; + } + + private Util() { + } +} diff --git a/bson/src/test/unit/org/bson/BsonDocumentTest.java b/bson/src/test/unit/org/bson/BsonDocumentTest.java index a352dab65a4..0ec2c007296 100644 --- a/bson/src/test/unit/org/bson/BsonDocumentTest.java +++ b/bson/src/test/unit/org/bson/BsonDocumentTest.java @@ -23,16 +23,13 @@ import org.bson.json.JsonReader; import org.bson.json.JsonWriter; import org.bson.json.JsonWriterSettings; -import org.junit.jupiter.api.Test; +import org.junit.Test; import java.io.StringWriter; import java.util.Arrays; -import java.util.function.Consumer; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; // Don't convert to Spock, as Groovy intercepts equals/hashCode methods that we are trying to test public class BsonDocumentTest { @@ -109,28 +106,4 @@ public void toStringShouldEqualToJson() { public void shouldParseJson() { assertEquals(new BsonDocument("a", new BsonInt32(1)), BsonDocument.parse("{\"a\" : 1}")); } - - @Test - public void cloneIsDeepCopyAndMutable() { - Consumer assertCloneDeepCopyMutable = original -> { - BsonDocument clone = original.clone(); - assertNotSame(original, clone); - assertEquals(original, clone); - // check that mutating `clone` does not mutate `original` - clone.getDocument("k1").put("k2", new BsonString("clone")); - assertEquals(new BsonString("clone"), clone.getDocument("k1").get("k2")); - assertEquals(BsonNull.VALUE, original.getDocument("k1").get("k2")); - // check that mutating `original` (if it is mutable) does not mutate `clone` - if (!(original instanceof RawBsonDocument)) { - original.put("k1", new BsonDocument("k2", new BsonString("original"))); - assertEquals(new BsonString("original"), original.getDocument("k1").get("k2")); - assertEquals(new BsonString("clone"), clone.getDocument("k1").get("k2")); - } - }; - assertAll( - () -> assertCloneDeepCopyMutable.accept(new BsonDocument("k1", new BsonDocument("k2", BsonNull.VALUE))), - () -> assertCloneDeepCopyMutable.accept(new BsonDocument("k1", RawBsonDocument.parse("{'k2': null}"))), - () -> assertCloneDeepCopyMutable.accept(RawBsonDocument.parse("{'k1': {'k2': null}}")) - ); - } } diff --git a/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy b/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy index 462d75b2a86..a23ec06dedb 100644 --- a/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy +++ b/bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy @@ -395,10 +395,11 @@ class RawBsonDocumentSpecification extends Specification { def 'clone should make a deep copy'() { when: - BsonDocument cloned = rawDocument.clone() + RawBsonDocument cloned = rawDocument.clone() then: - cloned.getClass() == BsonDocument + !cloned.getByteBuffer().array().is(createRawDocumenFromDocument().getByteBuffer().array()) + cloned.getByteBuffer().remaining() == rawDocument.getByteBuffer().remaining() cloned == createRawDocumenFromDocument() where: diff --git a/bson/src/test/unit/org/bson/internal/UtilTest.java b/bson/src/test/unit/org/bson/internal/UtilTest.java new file mode 100644 index 00000000000..4fe92a246a9 --- /dev/null +++ b/bson/src/test/unit/org/bson/internal/UtilTest.java @@ -0,0 +1,131 @@ +/* + * 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.BsonArray; +import org.bson.BsonBinary; +import org.bson.BsonDocument; +import org.bson.BsonDocumentWrapper; +import org.bson.BsonJavaScriptWithScope; +import org.bson.BsonValue; +import org.bson.RawBsonArray; +import org.bson.RawBsonDocument; +import org.bson.conversions.Bson; +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.Map.Entry; + +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; + +final class UtilTest { + @Test + public void mutableDeepCopy() { + Entry originalBsonBinaryEntry = new SimpleImmutableEntry<>( + "bsonBinary", + new BsonBinary("bsonBinary".getBytes(StandardCharsets.UTF_8)) + ); + Entry originalBsonJavaScriptWithScopeEntry = new SimpleImmutableEntry<>( + "bsonJavaScriptWithScopeEntry", + new BsonJavaScriptWithScope("\"use strict\";", new BsonDocument()) + ); + Entry originalRawBsonDocumentEntry = new SimpleImmutableEntry<>( + "rawBsonDocument", + RawBsonDocument.parse("{rawBsonDocument: 'rawBsonDocument_value'}") + ); + Entry> originalBsonDocumentWrapperEntry = new SimpleImmutableEntry<>( + "bsonDocumentWrapper", + new BsonDocumentWrapper<>(originalRawBsonDocumentEntry.getValue(), Bson.DEFAULT_CODEC_REGISTRY.get(RawBsonDocument.class)) + ); + Entry originalBsonDocumentEntry = new SimpleImmutableEntry<>( + "bsonDocument", + new BsonDocument() + .append(originalBsonBinaryEntry.getKey(), originalBsonBinaryEntry.getValue()) + .append(originalBsonJavaScriptWithScopeEntry.getKey(), originalBsonJavaScriptWithScopeEntry.getValue()) + .append(originalRawBsonDocumentEntry.getKey(), originalRawBsonDocumentEntry.getValue()) + .append(originalBsonDocumentWrapperEntry.getKey(), originalBsonDocumentWrapperEntry.getValue()) + ); + Entry originalBsonArrayEntry = new SimpleImmutableEntry<>( + "bsonArray", + new BsonArray(singletonList(new BsonArray())) + ); + Entry originalRawBsonArrayEntry = new SimpleImmutableEntry<>( + "rawBsonArray", + rawBsonArray( + originalBsonBinaryEntry.getValue(), + originalBsonJavaScriptWithScopeEntry.getValue(), + originalRawBsonDocumentEntry.getValue(), + originalBsonDocumentWrapperEntry.getValue(), + originalBsonDocumentEntry.getValue(), + originalBsonArrayEntry.getValue()) + ); + BsonDocument original = new BsonDocument() + .append(originalBsonBinaryEntry.getKey(), originalBsonBinaryEntry.getValue()) + .append(originalBsonJavaScriptWithScopeEntry.getKey(), originalBsonJavaScriptWithScopeEntry.getValue()) + .append(originalRawBsonDocumentEntry.getKey(), originalRawBsonDocumentEntry.getValue()) + .append(originalBsonDocumentWrapperEntry.getKey(), originalBsonDocumentWrapperEntry.getValue()) + .append(originalBsonDocumentEntry.getKey(), originalBsonDocumentEntry.getValue()) + .append(originalBsonArrayEntry.getKey(), originalBsonArrayEntry.getValue()) + .append(originalRawBsonArrayEntry.getKey(), originalRawBsonArrayEntry.getValue()); + BsonDocument copy = Util.mutableDeepCopy(original); + assertEqualNotSameAndMutable(original, copy); + original.forEach((key, value) -> assertEqualNotSameAndMutable(value, copy.get(key))); + // check nested document + String nestedDocumentKey = originalBsonDocumentEntry.getKey(); + BsonDocument originalNestedDocument = original.getDocument(nestedDocumentKey); + BsonDocument copyNestedDocument = copy.getDocument(nestedDocumentKey); + assertEqualNotSameAndMutable(originalNestedDocument, copyNestedDocument); + originalNestedDocument.forEach((key, value) -> assertEqualNotSameAndMutable(value, copyNestedDocument.get(key))); + // check nested array + String nestedArrayKey = originalRawBsonArrayEntry.getKey(); + BsonArray originalNestedArray = original.getArray(nestedArrayKey); + BsonArray copyNestedArray = copy.getArray(nestedArrayKey); + assertEqualNotSameAndMutable(originalNestedArray, copyNestedArray); + for (int i = 0; i < originalNestedArray.size(); i++) { + assertEqualNotSameAndMutable(originalNestedArray.get(i), copyNestedArray.get(i)); + } + } + + private static RawBsonArray rawBsonArray(final BsonValue... elements) { + return (RawBsonArray) new RawBsonDocument( + new BsonDocument("a", new BsonArray(asList(elements))), Bson.DEFAULT_CODEC_REGISTRY.get(BsonDocument.class)) + .get("a"); + } + + private static void assertEqualNotSameAndMutable(final Object expected, final Object actual) { + assertEquals(expected, actual); + assertNotSame(expected, actual); + Class actualClass = actual.getClass(); + if (expected instanceof BsonDocument) { + assertEquals(BsonDocument.class, actualClass); + } else if (expected instanceof BsonArray) { + assertEquals(BsonArray.class, actualClass); + } else if (expected instanceof BsonBinary) { + assertEquals(BsonBinary.class, actualClass); + } else if (expected instanceof BsonJavaScriptWithScope) { + assertEquals(BsonJavaScriptWithScope.class, actualClass); + } else { + org.bson.assertions.Assertions.fail("Unexpected " + expected.getClass().toString()); + } + } + + private UtilTest() { + } +} diff --git a/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java b/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java index 138e62f5d3f..8fe4bd820a9 100644 --- a/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java +++ b/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java @@ -27,6 +27,8 @@ import java.util.Optional; import java.util.function.Consumer; +import static org.bson.internal.Util.mutableDeepCopy; + /** * A {@link Bson} that allows constructing new instances via {@link #newAppended(String, Object)} instead of mutating {@code this}. * See {@link #AbstractConstructibleBson(Bson, Document)} for the note on mutability. @@ -141,7 +143,7 @@ public String toString() { } static BsonDocument newMerged(final BsonDocument base, final BsonDocument appended) { - BsonDocument result = base.clone(); + BsonDocument result = mutableDeepCopy(base); result.putAll(appended); return result; } diff --git a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java index 4887e0109a9..24cb5d8dbb2 100644 --- a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java +++ b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java @@ -63,6 +63,7 @@ import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static org.bson.internal.Util.mutableDeepCopy; /** *

This class is not part of the public API and may be removed or changed at any time

@@ -223,7 +224,7 @@ public Publisher createEncryptedCollection(final MongoDatabase dat return Mono.defer(() -> { // `Mono.defer` results in `maybeUpdatedEncryptedFields` and `dataKeyMightBeCreated` (mutable state) // being created once per `Subscriber`, which allows the produced `Mono` to support multiple `Subscribers`. - BsonDocument maybeUpdatedEncryptedFields = encryptedFields.clone(); + BsonDocument maybeUpdatedEncryptedFields = mutableDeepCopy(encryptedFields); AtomicBoolean dataKeyMightBeCreated = new AtomicBoolean(); Iterable> publishersOfUpdatedFields = () -> maybeUpdatedEncryptedFields.get("fields").asArray() .stream() diff --git a/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java b/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java index d1080245922..a328ad77bf5 100644 --- a/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java +++ b/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java @@ -58,6 +58,7 @@ import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static org.bson.internal.Util.mutableDeepCopy; /** *

This class is not part of the public API and may be removed or changed at any time

@@ -207,7 +208,7 @@ public BsonDocument createEncryptedCollection(final MongoDatabase database, fina dataKeyOptions.masterKey(masterKey); } String keyIdBsonKey = "keyId"; - BsonDocument maybeUpdatedEncryptedFields = encryptedFields.clone(); + BsonDocument maybeUpdatedEncryptedFields = mutableDeepCopy(encryptedFields); // only the mutability of `dataKeyMightBeCreated` is important, it does not need to be thread-safe AtomicBoolean dataKeyMightBeCreated = new AtomicBoolean(); try { From 3134e4a504b1fa407169e07ff5e84dc38e7351b7 Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Fri, 10 Feb 2023 08:10:03 -0700 Subject: [PATCH 3/4] Rename `Util` to `BsonUtil` JAVA-4874 --- .../src/main/org/bson/internal/{Util.java => BsonUtil.java} | 4 ++-- .../org/bson/internal/{UtilTest.java => BsonUtilTest.java} | 6 +++--- .../internal/client/model/AbstractConstructibleBson.java | 2 +- .../client/internal/vault/ClientEncryptionImpl.java | 2 +- .../com/mongodb/client/internal/ClientEncryptionImpl.java | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename bson/src/main/org/bson/internal/{Util.java => BsonUtil.java} (97%) rename bson/src/test/unit/org/bson/internal/{UtilTest.java => BsonUtilTest.java} (98%) diff --git a/bson/src/main/org/bson/internal/Util.java b/bson/src/main/org/bson/internal/BsonUtil.java similarity index 97% rename from bson/src/main/org/bson/internal/Util.java rename to bson/src/main/org/bson/internal/BsonUtil.java index 751e703b416..44326ff346f 100644 --- a/bson/src/main/org/bson/internal/Util.java +++ b/bson/src/main/org/bson/internal/BsonUtil.java @@ -24,7 +24,7 @@ /** *

This class is not part of the public API and may be removed or changed at any time

*/ -public final class Util { +public final class BsonUtil { public static BsonDocument mutableDeepCopy(final BsonDocument original) { BsonDocument copy = new BsonDocument(original.size()); original.forEach((key, value) -> copy.put(key, mutableDeepCopy(value))); @@ -68,6 +68,6 @@ private static T mutableDeepCopy(final T original) { return result; } - private Util() { + private BsonUtil() { } } diff --git a/bson/src/test/unit/org/bson/internal/UtilTest.java b/bson/src/test/unit/org/bson/internal/BsonUtilTest.java similarity index 98% rename from bson/src/test/unit/org/bson/internal/UtilTest.java rename to bson/src/test/unit/org/bson/internal/BsonUtilTest.java index 4fe92a246a9..8c41c45b1b3 100644 --- a/bson/src/test/unit/org/bson/internal/UtilTest.java +++ b/bson/src/test/unit/org/bson/internal/BsonUtilTest.java @@ -35,7 +35,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotSame; -final class UtilTest { +final class BsonUtilTest { @Test public void mutableDeepCopy() { Entry originalBsonBinaryEntry = new SimpleImmutableEntry<>( @@ -84,7 +84,7 @@ public void mutableDeepCopy() { .append(originalBsonDocumentEntry.getKey(), originalBsonDocumentEntry.getValue()) .append(originalBsonArrayEntry.getKey(), originalBsonArrayEntry.getValue()) .append(originalRawBsonArrayEntry.getKey(), originalRawBsonArrayEntry.getValue()); - BsonDocument copy = Util.mutableDeepCopy(original); + BsonDocument copy = BsonUtil.mutableDeepCopy(original); assertEqualNotSameAndMutable(original, copy); original.forEach((key, value) -> assertEqualNotSameAndMutable(value, copy.get(key))); // check nested document @@ -126,6 +126,6 @@ private static void assertEqualNotSameAndMutable(final Object expected, final Ob } } - private UtilTest() { + private BsonUtilTest() { } } diff --git a/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java b/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java index 8fe4bd820a9..278f7e273be 100644 --- a/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java +++ b/driver-core/src/main/com/mongodb/internal/client/model/AbstractConstructibleBson.java @@ -27,7 +27,7 @@ import java.util.Optional; import java.util.function.Consumer; -import static org.bson.internal.Util.mutableDeepCopy; +import static org.bson.internal.BsonUtil.mutableDeepCopy; /** * A {@link Bson} that allows constructing new instances via {@link #newAppended(String, Object)} instead of mutating {@code this}. diff --git a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java index 24cb5d8dbb2..5b4331fa982 100644 --- a/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java +++ b/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/vault/ClientEncryptionImpl.java @@ -63,7 +63,7 @@ import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.bson.internal.Util.mutableDeepCopy; +import static org.bson.internal.BsonUtil.mutableDeepCopy; /** *

This class is not part of the public API and may be removed or changed at any time

diff --git a/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java b/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java index a328ad77bf5..b8462f058c2 100644 --- a/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java +++ b/driver-sync/src/main/com/mongodb/client/internal/ClientEncryptionImpl.java @@ -58,7 +58,7 @@ import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -import static org.bson.internal.Util.mutableDeepCopy; +import static org.bson.internal.BsonUtil.mutableDeepCopy; /** *

This class is not part of the public API and may be removed or changed at any time

From a34d0ff88b81deb6cababceecd14ac4bf3711345 Mon Sep 17 00:00:00 2001 From: Valentin Kovalenko Date: Mon, 13 Feb 2023 11:06:50 -0700 Subject: [PATCH 4/4] `BsonUtil.mutableDeepCopy` does not need to be generic JAVA-4874 --- bson/src/main/org/bson/internal/BsonUtil.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/bson/src/main/org/bson/internal/BsonUtil.java b/bson/src/main/org/bson/internal/BsonUtil.java index 44326ff346f..6879c4c0e12 100644 --- a/bson/src/main/org/bson/internal/BsonUtil.java +++ b/bson/src/main/org/bson/internal/BsonUtil.java @@ -45,27 +45,19 @@ private static BsonJavaScriptWithScope mutableDeepCopy(final BsonJavaScriptWithS return new BsonJavaScriptWithScope(original.getCode(), mutableDeepCopy(original.getScope())); } - private static T mutableDeepCopy(final T original) { - BsonValue copy; + private static BsonValue mutableDeepCopy(final BsonValue original) { switch (original.getBsonType()) { case DOCUMENT: - copy = mutableDeepCopy(original.asDocument()); - break; + return mutableDeepCopy(original.asDocument()); case ARRAY: - copy = mutableDeepCopy(original.asArray()); - break; + return mutableDeepCopy(original.asArray()); case BINARY: - copy = mutableDeepCopy(original.asBinary()); - break; + return mutableDeepCopy(original.asBinary()); case JAVASCRIPT_WITH_SCOPE: - copy = mutableDeepCopy(original.asJavaScriptWithScope()); - break; + return mutableDeepCopy(original.asJavaScriptWithScope()); default: - copy = original; + return original; } - @SuppressWarnings("unchecked") - T result = (T) copy; - return result; } private BsonUtil() {