Skip to content

Commit 0282a7e

Browse files
authored
JAVA-5342 Fix encoding generics with nullable type parameters (#1317)
1 parent e283f57 commit 0282a7e

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

bson-kotlinx/src/main/kotlin/org/bson/codecs/kotlinx/BsonEncoder.kt

+20-1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,18 @@ internal class DefaultBsonEncoder(
139139
return true
140140
}
141141

142+
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) {
143+
deferredElementName?.let {
144+
if (value != null || configuration.explicitNulls) {
145+
encodeName(it)
146+
super.encodeSerializableValue(serializer, value)
147+
} else {
148+
deferredElementName = null
149+
}
150+
}
151+
?: super.encodeSerializableValue(serializer, value)
152+
}
153+
142154
override fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) {
143155
deferredElementName?.let {
144156
if (value != null || configuration.explicitNulls) {
@@ -158,7 +170,14 @@ internal class DefaultBsonEncoder(
158170
override fun encodeDouble(value: Double) = writer.writeDouble(value)
159171
override fun encodeInt(value: Int) = writer.writeInt32(value)
160172
override fun encodeLong(value: Long) = writer.writeInt64(value)
161-
override fun encodeNull() = writer.writeNull()
173+
override fun encodeNull() {
174+
deferredElementName?.let {
175+
if (configuration.explicitNulls) {
176+
encodeName(it)
177+
}
178+
}
179+
writer.writeNull()
180+
}
162181

163182
override fun encodeString(value: String) {
164183
when (state) {

bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/KotlinSerializerCodecTest.kt

+23
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import org.bson.BsonUndefined
3333
import org.bson.codecs.DecoderContext
3434
import org.bson.codecs.EncoderContext
3535
import org.bson.codecs.configuration.CodecConfigurationException
36+
import org.bson.codecs.kotlinx.samples.Box
3637
import org.bson.codecs.kotlinx.samples.DataClassBsonValues
3738
import org.bson.codecs.kotlinx.samples.DataClassContainsOpen
3839
import org.bson.codecs.kotlinx.samples.DataClassContainsValueClass
@@ -76,6 +77,7 @@ import org.bson.codecs.kotlinx.samples.DataClassWithMutableMap
7677
import org.bson.codecs.kotlinx.samples.DataClassWithMutableSet
7778
import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterized
7879
import org.bson.codecs.kotlinx.samples.DataClassWithNestedParameterizedDataClass
80+
import org.bson.codecs.kotlinx.samples.DataClassWithNullableGeneric
7981
import org.bson.codecs.kotlinx.samples.DataClassWithNulls
8082
import org.bson.codecs.kotlinx.samples.DataClassWithPair
8183
import org.bson.codecs.kotlinx.samples.DataClassWithParameterizedDataClass
@@ -202,6 +204,27 @@ class KotlinSerializerCodecTest {
202204
assertRoundTrips(expectedNulls, dataClass, altConfiguration)
203205
}
204206

207+
@Test
208+
fun testDataClassWithNullableGenericsNotNull() {
209+
val expected =
210+
"""{
211+
| "box": {"boxed": "String"}
212+
|}"""
213+
.trimMargin()
214+
215+
val dataClass = DataClassWithNullableGeneric(Box("String"))
216+
assertRoundTrips(expected, dataClass)
217+
}
218+
219+
@Test
220+
fun testDataClassWithNullableGenericsNull() {
221+
val expectedDefault = """{"box": {}}"""
222+
val dataClass = DataClassWithNullableGeneric(Box(null))
223+
assertRoundTrips(expectedDefault, dataClass)
224+
val expectedNull = """{"box": {"boxed": null}}"""
225+
assertRoundTrips(expectedNull, dataClass, altConfiguration)
226+
}
227+
205228
@Test
206229
fun testDataClassSelfReferential() {
207230
val expected =

bson-kotlinx/src/test/kotlin/org/bson/codecs/kotlinx/samples/DataClasses.kt

+4
Original file line numberDiff line numberDiff line change
@@ -294,3 +294,7 @@ data class DataClassWithFailingInit(val id: String) {
294294
}
295295

296296
@Serializable data class DataClassWithSequence(val value: Sequence<String>)
297+
298+
@Serializable data class Box<T>(val boxed: T)
299+
300+
@Serializable data class DataClassWithNullableGeneric(val box: Box<String?>)

0 commit comments

Comments
 (0)