Skip to content

Fix Kotlin bson decoding of optionals#1941

Merged
rozza merged 3 commits intomongodb:mainfrom
rozza:JAVA-6162
Apr 28, 2026
Merged

Fix Kotlin bson decoding of optionals#1941
rozza merged 3 commits intomongodb:mainfrom
rozza:JAVA-6162

Conversation

@rozza
Copy link
Copy Markdown
Member

@rozza rozza commented Apr 13, 2026

Previously, DataClassCodec pre-populated all constructor parameters with null before reading the document, which prevented callBy from using Kotlin default parameter values.

Now optional parameters missing from the document are left absent from the args map so callBy invokes their defaults, and a clear CodecConfigurationException is thrown when a required non-nullable field is missing.

Ported the bson-kotlin test cases to bson-kotlinx to ensure coverage and prevent future regressions.

JAVA-6162

Previously, DataClassCodec pre-populated all constructor parameters with
null before reading the document, which prevented callBy from using
Kotlin default parameter values.

Now optional parameters missing from the document are left absent from
the args map so callBy invokes their defaults, and a clear
CodecConfigurationException is thrown when a required non-nullable field
is missing.

Ported the bson-kotlin test cases to bson-kotlinx to ensure coverage
and prevent future regressions.

JAVA-6162
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Kotlin BSON decoding of data classes so that missing optional constructor parameters can correctly fall back to Kotlin default parameter values, while missing required non-nullable fields fail with a clear exception. Adds/updates test coverage (ported from bson-kotlin to bson-kotlinx) around defaults + null-handling to prevent regressions.

Changes:

  • Update DataClassCodec.decode to stop pre-populating constructor args with null, and to validate missing required fields after reading the document.
  • Add a new DataClassWithDefaultsAndNulls sample in both bson-kotlin and bson-kotlinx.
  • Expand tests in both modules to explicitly assert decoding behavior for missing fields vs explicit nulls vs defaults.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt Adds DataClassWithDefaultsAndNulls sample for kotlinx-serialization codec tests.
bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt Adds decode assertions for defaults/nulls and a missing-required-field failure case.
bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/samples/DataClasses.kt Adds DataClassWithDefaultsAndNulls sample for reflection-based DataClassCodec tests.
bson-kotlin/src/test/kotlin/org/bson/codecs/kotlin/DataClassCodecTest.kt Expands tests to assert decoding behavior for defaults/nulls and missing required field exception.
bson-kotlin/src/main/kotlin/org/bson/codecs/kotlin/DataClassCodec.kt Core logic change: don’t prefill args with null; validate missing required fields and preserve defaults via callBy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rozza rozza requested a review from Copilot April 13, 2026 15:53
@rozza rozza marked this pull request as ready for review April 13, 2026 15:53
@rozza rozza requested a review from a team as a code owner April 13, 2026 15:53
@rozza rozza requested a review from vbabanin April 13, 2026 15:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rozza rozza requested review from strogiyotec and removed request for vbabanin April 21, 2026 10:41
Copy link
Copy Markdown
Contributor

@strogiyotec strogiyotec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM , checked these changes locally, thanks Ross

@strogiyotec
Copy link
Copy Markdown
Contributor

@rozza the only thing I noticed is a small behavior change

    @Test
    fun testMissingRequiredNonNullableFieldThrows() {
        // Before this PR: args map was pre-seeded with nulls, so a missing non-nullable field
        // would silently end up as `null` in the constructed object (reflection bypasses
        // Kotlin's null-safety), or surface as an opaque callBy failure.
        //
        // After this PR: the codec detects the missing non-nullable field and throws a clear
        // CodecConfigurationException naming the field.
        val incomplete = BsonDocument.parse(
            """{"char": "c", "byte": 0, "short": 1, "int": 22,
             | "long": {"$numberLong": "42"}, "float": 4.0,
             | "double": 4.2, "boolean": true}""".trimMargin()
            // note: "string" field is missing
        )

        val codec = DataClassCodec.create(DataClassWithSimpleValues::class, registry())

        val ex = assertThrows<CodecConfigurationException> {
            codec?.decode(BsonDocumentReader(incomplete), DecoderContext.builder().build())
        }
        assertEquals(
            "Required field 'string' is missing from the document for DataClassWithSimpleValues data class",
            ex.message
        )
    }

data class DataClassWithSimpleValues(
    val char: Char,
    val byte: Byte,
    val short: Short,
    val int: Int,
    val long: Long,
    val float: Float,
    val double: Double,
    val boolean: Boolean,
    val string: String
)

With this PR , the test case will throw CodecConfigurationException with error message

Required field 'string' is missing from the document for DataClassWithSimpleValues data class

Previously this test case created an instance of DataClassWithSimpleValues with null string

I guess it's worth mentioning in the release notes

@rozza
Copy link
Copy Markdown
Member Author

rozza commented Apr 28, 2026

@strogiyotec

Previously this test case created an instance of DataClassWithSimpleValues with null string

In this case the call to return primaryConstructor.callBy(args) fails and we throw:

org.bson.codecs.configuration.CodecConfigurationException: Unable to invoke primary constructor of DataClassWithSimpleValues data class

So the change here is the error message is more specific and helpful for the user.

@rozza rozza merged commit e9c0c4b into mongodb:main Apr 28, 2026
51 of 53 checks passed
@rozza rozza deleted the JAVA-6162 branch April 28, 2026 10:01
nhachicha pushed a commit to nhachicha/mongo-java-driver that referenced this pull request Apr 29, 2026
* Fix Kotlin bson decoding of optionals

Previously, DataClassCodec pre-populated all constructor parameters with
null before reading the document, which prevented callBy from using
Kotlin default parameter values.

Now optional parameters missing from the document are left absent from
the args map so callBy invokes their defaults, and a clear
CodecConfigurationException is thrown when a required non-nullable field
is missing.

Ported the bson-kotlin test cases to bson-kotlinx to ensure coverage
and prevent future regressions.

JAVA-6162
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants