From 11a4f923ec42f7ff85b9686ae912cf7c349be9c9 Mon Sep 17 00:00:00 2001 From: Cliffred van Velzen Date: Mon, 1 Jul 2024 15:09:49 +0200 Subject: [PATCH] JAVA-5342 Fix encoding generics with nullable type parameters (#1317) --- .../org/bson/codecs/kotlinx/BsonEncoder.kt | 21 ++++++++++++++++- .../kotlinx/KotlinSerializerCodecTest.kt | 23 +++++++++++++++++++ .../codecs/kotlinx/samples/DataClasses.kt | 4 ++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt index 2e68b992700..b3ae0c8cdf4 100644 --- a/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt +++ b/bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt @@ -139,6 +139,18 @@ internal class DefaultBsonEncoder( return true } + override fun encodeSerializableValue(serializer: SerializationStrategy, value: T) { + deferredElementName?.let { + if (value != null || configuration.explicitNulls) { + encodeName(it) + super.encodeSerializableValue(serializer, value) + } else { + deferredElementName = null + } + } + ?: super.encodeSerializableValue(serializer, value) + } + override fun encodeNullableSerializableValue(serializer: SerializationStrategy, value: T?) { deferredElementName?.let { if (value != null || configuration.explicitNulls) { @@ -158,7 +170,14 @@ internal class DefaultBsonEncoder( override fun encodeDouble(value: Double) = writer.writeDouble(value) override fun encodeInt(value: Int) = writer.writeInt32(value) override fun encodeLong(value: Long) = writer.writeInt64(value) - override fun encodeNull() = writer.writeNull() + override fun encodeNull() { + deferredElementName?.let { + if (configuration.explicitNulls) { + encodeName(it) + } + } + writer.writeNull() + } override fun encodeString(value: String) { when (state) { diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt index 14fcfa8a01c..0aed60b27ba 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt @@ -33,6 +33,7 @@ import org.bson.BsonUndefined import org.bson.codecs.DecoderContext import org.bson.codecs.EncoderContext import org.bson.codecs.configuration.CodecConfigurationException +import org.bson.codecs.kotlinx.samples.Box import org.bson.codecs.kotlinx.samples.DataClassBsonValues import org.bson.codecs.kotlinx.samples.DataClassContainsOpen import org.bson.codecs.kotlinx.samples.DataClassContainsValueClass @@ -76,6 +77,7 @@ import org.bson.codecs.kotlinx.samples.DataClassWithMutableMap import org.bson.codecs.kotlinx.samples.DataClassWithMutableSet import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterized import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterizedDataClass +import org.bson.codecs.kotlinx.samples.DataClassWithNullableGeneric import org.bson.codecs.kotlinx.samples.DataClassWithNulls import org.bson.codecs.kotlinx.samples.DataClassWithPair import org.bson.codecs.kotlinx.samples.DataClassWithParameterizedDataClass @@ -202,6 +204,27 @@ class KotlinSerializerCodecTest { assertRoundTrips(expectedNulls, dataClass, altConfiguration) } + @Test + fun testDataClassWithNullableGenericsNotNull() { + val expected = + """{ + | "box": {"boxed": "String"} + |}""" + .trimMargin() + + val dataClass = DataClassWithNullableGeneric(Box("String")) + assertRoundTrips(expected, dataClass) + } + + @Test + fun testDataClassWithNullableGenericsNull() { + val expectedDefault = """{"box": {}}""" + val dataClass = DataClassWithNullableGeneric(Box(null)) + assertRoundTrips(expectedDefault, dataClass) + val expectedNull = """{"box": {"boxed": null}}""" + assertRoundTrips(expectedNull, dataClass, altConfiguration) + } + @Test fun testDataClassSelfReferential() { val expected = diff --git a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt index 0326827d4a7..a58ae541d03 100644 --- a/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt +++ b/bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt @@ -294,3 +294,7 @@ data class DataClassWithFailingInit(val id: String) { } @Serializable data class DataClassWithSequence(val value: Sequence) + +@Serializable data class Box(val boxed: T) + +@Serializable data class DataClassWithNullableGeneric(val box: Box)