[JAVA-5103] A custom codec that fails to write the name causes a NPE Created: 09/Aug/23  Updated: 14/Aug/23

Status: Backlog
Project: Java Driver
Component/s: BSON
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Minor - P4
Reporter: Ross Lawley Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to JAVA-5099 Driver is using Kotlin native seriali... Closed

 Description   

The following exception is thrown when the writer doesn't write the name:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "org.bson.BsonBinaryWriter$Context.getContextType()" because the return value of "org.bson.BsonBinaryWriter.getContext()" is null
	at org.bson.BsonBinaryWriter.writeCurrentName(BsonBinaryWriter.java:403)
	at org.bson.BsonBinaryWriter.doWriteBinaryData(BsonBinaryWriter.java:160)
	at org.bson.AbstractBsonWriter.writeBinaryData(AbstractBsonWriter.java:368)
	at com.mongodb.internal.connection.BsonWriterDecorator.writeBinaryData(BsonWriterDecorator.java:81)
	at com.mongodb.internal.connection.IdHoldingBsonWriter.writeBinaryData(IdHoldingBsonWriter.java:155)

Seems getContext() can return null and this error could be friendlier to describe why.

Here is a Kotlin based example that triggers the error (the Java equivalent would also error).

@JvmInline
value class Image(@Contextual val binary: BsonBinary)
 
class ImageCodec : Codec<Image> {
    override fun encode(writer: BsonWriter, value: Image, encoderContext: EncoderContext) {
        writer.writeBinaryData(value.binary)
    }
 
    override fun decode(reader: BsonReader, decoderContext: DecoderContext): Image {
        return Image(reader.readBinaryData())
    }
 
    override fun getEncoderClass(): Class<Image> = Image::class.java
}
 
fun main() {
 
    val codecRegistry = CodecRegistries.fromRegistries(
        CodecRegistries.fromCodecs(ImageCodec()),
        MongoClientSettings.getDefaultCodecRegistry()
    )
 
    val mongoClient = MongoClient.create("mongodb://localhost/")
 
    val db = mongoClient.getDatabase("test")
        .withCodecRegistry(codecRegistry)
 
    val img = Image(BsonBinary("asdfasdf".toByteArray()))
 
    val collection = db.getCollection<Image>("test")
    collection.drop()
 
    println(collection.insertOne(img))
    println(collection.find().toCollection(mutableListOf()))
 
    mongoClient.close()
}

A full fix for this bug should consider the behavior or all BsonWriter implementations, as it looks like BsonBinaryWriter is not the only one that will NPE:

java.lang.NullPointerException: Cannot invoke "org.bson.BsonDocument.put(String, org.bson.BsonValue)" because "this.container" is null
	at org.bson.BsonDocumentWriter$Context.add(BsonDocumentWriter.java:226)
	at org.bson.BsonDocumentWriter.write(BsonDocumentWriter.java:207)
	at org.bson.BsonDocumentWriter.doWriteBoolean(BsonDocumentWriter.java:109)
	at org.bson.AbstractBsonWriter.writeBoolean(AbstractBsonWriter.java:381)


Generated at Thu Feb 08 09:03:45 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.