Skip to content

Commit d439e79

Browse files
committed
Make sure that BsonDocument.clone returns a mutable deep copy
1 parent 59585de commit d439e79

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

bson/src/main/org/bson/RawBsonDocument.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ public int hashCode() {
328328

329329
@Override
330330
public BsonDocument clone() {
331-
return new RawBsonDocument(bytes.clone(), offset, length);
331+
return toBaseBsonDocument();
332332
}
333333

334334
private BsonBinaryReader createReader() {

bson/src/test/unit/org/bson/BsonDocumentTest.java

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@
2323
import org.bson.json.JsonReader;
2424
import org.bson.json.JsonWriter;
2525
import org.bson.json.JsonWriterSettings;
26-
import org.junit.Test;
26+
import org.junit.jupiter.api.Test;
2727

2828
import java.io.StringWriter;
2929
import java.util.Arrays;
30+
import java.util.function.Consumer;
3031

31-
import static org.junit.Assert.assertEquals;
32-
import static org.junit.Assert.assertNotEquals;
32+
import static org.junit.jupiter.api.Assertions.assertAll;
33+
import static org.junit.jupiter.api.Assertions.assertEquals;
34+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
35+
import static org.junit.jupiter.api.Assertions.assertNotSame;
3336

3437
// Don't convert to Spock, as Groovy intercepts equals/hashCode methods that we are trying to test
3538
public class BsonDocumentTest {
@@ -106,4 +109,28 @@ public void toStringShouldEqualToJson() {
106109
public void shouldParseJson() {
107110
assertEquals(new BsonDocument("a", new BsonInt32(1)), BsonDocument.parse("{\"a\" : 1}"));
108111
}
112+
113+
@Test
114+
public void cloneIsDeepCopyAndMutable() {
115+
Consumer<BsonDocument> assertCloneDeepCopyMutable = original -> {
116+
BsonDocument clone = original.clone();
117+
assertNotSame(original, clone);
118+
assertEquals(original, clone);
119+
// check that mutating `clone` does not mutate `original`
120+
clone.getDocument("k1").put("k2", new BsonString("clone"));
121+
assertEquals(new BsonString("clone"), clone.getDocument("k1").get("k2"));
122+
assertEquals(BsonNull.VALUE, original.getDocument("k1").get("k2"));
123+
// check that mutating `original` (if it is mutable) does not mutate `clone`
124+
if (!(original instanceof RawBsonDocument)) {
125+
original.put("k1", new BsonDocument("k2", new BsonString("original")));
126+
assertEquals(new BsonString("original"), original.getDocument("k1").get("k2"));
127+
assertEquals(new BsonString("clone"), clone.getDocument("k1").get("k2"));
128+
}
129+
};
130+
assertAll(
131+
() -> assertCloneDeepCopyMutable.accept(new BsonDocument("k1", new BsonDocument("k2", BsonNull.VALUE))),
132+
() -> assertCloneDeepCopyMutable.accept(new BsonDocument("k1", RawBsonDocument.parse("{'k2': null}"))),
133+
() -> assertCloneDeepCopyMutable.accept(RawBsonDocument.parse("{'k1': {'k2': null}}"))
134+
);
135+
}
109136
}

bson/src/test/unit/org/bson/RawBsonDocumentSpecification.groovy

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,11 +395,10 @@ class RawBsonDocumentSpecification extends Specification {
395395

396396
def 'clone should make a deep copy'() {
397397
when:
398-
RawBsonDocument cloned = rawDocument.clone()
398+
BsonDocument cloned = rawDocument.clone()
399399

400400
then:
401-
!cloned.getByteBuffer().array().is(createRawDocumenFromDocument().getByteBuffer().array())
402-
cloned.getByteBuffer().remaining() == rawDocument.getByteBuffer().remaining()
401+
cloned.getClass() == BsonDocument
403402
cloned == createRawDocumenFromDocument()
404403

405404
where:

0 commit comments

Comments
 (0)