Skip to content

Commit 36d0e7f

Browse files
authored
Scala: Ensure implicit conversion keeps type fidelity (#627)
When converting from a BsonDocument to org.bson.Document the scala driver previously used json. The implementation should not rely on the json output format, but rather use the Codecs to do the conversion. JAVA-3916
1 parent ba2785e commit 36d0e7f

File tree

2 files changed

+46
-12
lines changed

2 files changed

+46
-12
lines changed

driver-scala/src/main/scala/org/mongodb/scala/package.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616

1717
package org.mongodb
1818

19-
import _root_.scala.language.implicitConversions
20-
import _root_.scala.reflect.ClassTag
19+
import org.bson.BsonDocumentReader
20+
import org.bson.codecs.{ DecoderContext, DocumentCodec }
2121
import org.mongodb.scala.bson.BsonDocument
2222
import org.mongodb.scala.internal.WriteConcernImplicits
2323

24+
import _root_.scala.language.implicitConversions
25+
import _root_.scala.reflect.ClassTag
26+
2427
/**
2528
* The MongoDB Scala Driver package
2629
*
@@ -392,9 +395,12 @@ package object scala extends ClientSessionImplicits with ObservableImplicits wit
392395

393396
implicit def bsonDocumentToDocument(doc: BsonDocument): Document = new Document(doc)
394397

395-
implicit def bsonDocumentToUntypedDocument(doc: BsonDocument): org.bson.Document =
396-
org.bson.Document.parse(doc.toJson())
398+
implicit def documentToUntypedDocument(doc: Document): org.bson.Document =
399+
bsonDocumentToUntypedDocument(doc.underlying)
397400

398-
implicit def documentToUntypedDocument(doc: Document): org.bson.Document = org.bson.Document.parse(doc.toJson())
401+
private lazy val DOCUMENT_CODEC = new DocumentCodec()
402+
implicit def bsonDocumentToUntypedDocument(doc: BsonDocument): org.bson.Document = {
403+
DOCUMENT_CODEC.decode(new BsonDocumentReader(doc), DecoderContext.builder().build())
404+
}
399405

400406
}

driver-scala/src/test/scala/org/mongodb/scala/ScalaPackageSpec.scala

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717
package org.mongodb.scala
1818

1919
import java.util.concurrent.TimeUnit
20-
2120
import _root_.scala.concurrent.duration.Duration
22-
2321
import com.mongodb.{ MongoCredential => JMongoCredential }
24-
22+
import org.bson.BsonDocumentWrapper
23+
import org.bson.codecs.DocumentCodec
2524
import org.mongodb.scala
26-
import org.mongodb.scala.bson.BsonString
25+
import org.mongodb.scala.MongoClient.DEFAULT_CODEC_REGISTRY
26+
import org.mongodb.scala.bson._
2727
import org.mongodb.scala.model._
28-
import org.scalatest.{ FlatSpec, Matchers }
2928

3029
class ScalaPackageSpec extends BaseSpec {
3130

@@ -66,9 +65,9 @@ class ScalaPackageSpec extends BaseSpec {
6665

6766
it should "be able to create Documents" in {
6867
val doc = Document("a" -> BsonString("1"))
69-
val doc2 = org.mongodb.scala.bson.collection.Document("a" -> BsonString("1"))
68+
val doc2 = collection.Document("a" -> BsonString("1"))
7069

71-
doc shouldBe a[org.mongodb.scala.bson.collection.immutable.Document]
70+
doc shouldBe a[collection.immutable.Document]
7271
doc should equal(doc2)
7372
}
7473

@@ -141,4 +140,33 @@ class ScalaPackageSpec extends BaseSpec {
141140
val javaCredential5 = JMongoCredential.createGSSAPICredential("userName")
142141
scalaCredential5 should equal(javaCredential5)
143142
}
143+
144+
it should "implicitly convert to org.bson.document with type fidelity" in {
145+
146+
val bsonDocument = Document(
147+
"null" -> BsonNull(),
148+
"int32" -> BsonInt32(32),
149+
"int64" -> BsonInt64(Long.MaxValue),
150+
"decimal128" -> BsonDecimal128(128.1),
151+
"boolean" -> BsonBoolean(true),
152+
"date" -> BsonDateTime(123456789),
153+
"double" -> BsonDouble(1.1),
154+
"string" -> BsonString("String"),
155+
"minKey" -> BsonMinKey(),
156+
"maxKey" -> BsonMaxKey(),
157+
"javaScript" -> BsonJavaScript("function () {}"),
158+
"objectId" -> BsonObjectId(),
159+
"codeWithScope" -> BsonJavaScriptWithScope("function () {}", Document()),
160+
"regex" -> BsonRegularExpression("/(.*)/"),
161+
"symbol" -> BsonSymbol(Symbol("sym")),
162+
"timestamp" -> BsonTimestamp(),
163+
"undefined" -> BsonUndefined(),
164+
"binary" -> BsonBinary(Array[Byte](128.toByte)),
165+
"array" -> BsonArray(List("a", "b", "c")),
166+
"document" -> Document("a" -> 1, "b" -> List(1, 2, 3))
167+
)
168+
169+
val document: org.bson.Document = bsonDocument
170+
BsonDocumentWrapper.asBsonDocument(document, DEFAULT_CODEC_REGISTRY) should equal(bsonDocument.underlying)
171+
}
144172
}

0 commit comments

Comments
 (0)