Hello,
I’m using Kotlin driver => org.mongodb:mongodb-driver-kotlin-sync:4.10.2
(the same issue exists in org.mongodb:mongodb-driver-kotlin-coroutine:4.10.1 too)
I have a data class with a nullable String field
data class MyData(
val myfield: String?
)
When I read the value from the DB, here are what is printed on console :
-
if myfield does NOT exist in the DB => it successfully prints “MyData(myfield=null)”
-
if myfield exists and contains “myvalue” => it successfully prints “MyData(myfield=myvalue)”
-
if myfield exists and contains null value (BSONType is NULL) => I would expect that it prints “MyData(myfield=null)” but it is not!? It throws the BsonInvalidOperationException “readString can only be called when CurrentBSONType is STRING, not when CurrentBSONType is NULL.”
Could you please tell me what’s wrong? Thanks!
Full exception trace
Exception in thread "main" org.bson.codecs.configuration.CodecConfigurationException: Unable to decode myfield for MyData data class.
at org.bson.codecs.kotlin.DataClassCodec.decode(DataClassCodec.kt:92)
at com.mongodb.internal.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)
at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:60)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:87)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
at org.bson.internal.LazyCodec.decode(LazyCodec.java:53)
at org.bson.codecs.BsonDocumentCodec.readValue(BsonDocumentCodec.java:104)
at com.mongodb.internal.operation.CommandResultDocumentCodec.readValue(CommandResultDocumentCodec.java:63)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:87)
at org.bson.codecs.BsonDocumentCodec.decode(BsonDocumentCodec.java:42)
at com.mongodb.internal.connection.ReplyMessage.<init>(ReplyMessage.java:48)
at com.mongodb.internal.connection.InternalStreamConnection.getCommandResult(InternalStreamConnection.java:565)
at com.mongodb.internal.connection.InternalStreamConnection.receiveCommandMessageResponse(InternalStreamConnection.java:455)
at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:370)
at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:114)
at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:719)
at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:76)
at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:203)
at com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:115)
at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:83)
at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:74)
at com.mongodb.internal.connection.DefaultServer$OperationCountTrackingConnection.command(DefaultServer.java:287)
at com.mongodb.internal.operation.CommandOperationHelper.createReadCommandAndExecute(CommandOperationHelper.java:245)
at com.mongodb.internal.operation.FindOperation.lambda$execute$1(FindOperation.java:324)
at com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$0(OperationHelper.java:345)
at com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:370)
at com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$1(OperationHelper.java:344)
at com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:370)
at com.mongodb.internal.operation.OperationHelper.withSourceAndConnection(OperationHelper.java:343)
at com.mongodb.internal.operation.FindOperation.lambda$execute$2(FindOperation.java:321)
at com.mongodb.internal.operation.CommandOperationHelper.lambda$decorateReadWithRetries$3(CommandOperationHelper.java:192)
at com.mongodb.internal.async.function.RetryingSyncSupplier.get(RetryingSyncSupplier.java:67)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:332)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:72)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:153)
at com.mongodb.client.internal.FindIterableImpl.first(FindIterableImpl.java:213)
at com.mongodb.kotlin.client.MongoIterable.firstOrNull(MongoIterable.kt:38)
at MainKt.main(Main.kt:20)
Caused by: org.bson.BsonInvalidOperationException: readString can only be called when CurrentBSONType is STRING, not when CurrentBSONType is NULL.
at org.bson.AbstractBsonReader.verifyBSONType(AbstractBsonReader.java:689)
at org.bson.AbstractBsonReader.checkPreconditions(AbstractBsonReader.java:721)
at org.bson.AbstractBsonReader.readString(AbstractBsonReader.java:456)
at org.bson.codecs.StringCodec.decode(StringCodec.java:80)
at org.bson.codecs.StringCodec.decode(StringCodec.java:31)
at org.bson.codecs.DecoderContext.decodeWithChildContext(DecoderContext.java:96)
at org.bson.codecs.kotlin.DataClassCodec.decode(DataClassCodec.kt:90)
... 37 more
Here is a very simple code to reproduce (replace XXX, YYY, ZZZ with your values)
data class MyData(
val myfield: String?
)
fun main(args: Array<String>) {
val uri = "XXXXXXXXX"
val databaseName = "YYYYYYYY"
val collectionName = "ZZZZZZZ"
val mongoClient = MongoClient.create(uri)
val db = mongoClient.getDatabase(databaseName)
val collection = db.getCollection<MyData>(collectionName)
val doc = collection.find().firstOrNull()
if (doc != null) {
println(doc)
} else {
println("No matching documents found.")
}
mongoClient.close()
}
If needed, here is my build.gradle.kts
build.gradle.kts
plugins {
kotlin("jvm") version "1.9.10"
application
}
group = "org.example"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
implementation("org.mongodb:mongodb-driver-kotlin-sync:4.10.2")
//implementation("org.mongodb:mongodb-driver-kotlin-coroutine:4.10.1")
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(8)
}
application {
mainClass.set("MainKt")
}
Thanks for your help!