From 25172c42658bd613e8af6e0c05716144009d86e3 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Tue, 21 Jan 2025 17:23:44 +0100 Subject: [PATCH 1/2] Make type argument in JsonTransformingSerializer nullable This will allow for more flexible Json transformations, replacing invalid/unexpected input data with `null`s. Fixes #1927 --- .../json/JsonTransformingSerializerTest.kt | 25 +++++++++++++++++++ .../json/JsonTransformingSerializer.kt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt index 516587f5ed..9398e95f40 100644 --- a/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt +++ b/formats/json-tests/commonTest/src/kotlinx/serialization/json/JsonTransformingSerializerTest.kt @@ -98,4 +98,29 @@ class JsonTransformingSerializerTest : JsonTestBase() { assertEquals(correctExample, json.decodeFromString(DocExample.serializer(), """{"data":["str1"]}""", streaming)) assertEquals(correctExample, json.decodeFromString(DocExample.serializer(), """{"data":"str1"}""", streaming)) } + + // Wraps/unwraps {"data":null} to just `null`, because StringData.data is not nullable + object NullableStringDataSerializer : JsonTransformingSerializer(StringData.serializer().nullable) { + override fun transformDeserialize(element: JsonElement): JsonElement { + val data = element.jsonObject["data"]?.jsonPrimitive + if (data?.contentOrNull.isNullOrBlank()) return JsonNull + return element + } + + override fun transformSerialize(element: JsonElement): JsonElement { + return if (element is JsonNull) JsonObject(mapOf("data" to JsonNull)) + else element + } + } + + @Serializable + data class NullableStringDataHolder(@Serializable(NullableStringDataSerializer::class) val stringData: StringData?) + + @Test + fun testNullableTransformingSerializer() { + val normalInput = """{"stringData":{"data":"str1"}}""" + val nullInput = """{"stringData":{"data":null}}""" + assertJsonFormAndRestored(NullableStringDataHolder.serializer(), NullableStringDataHolder(StringData("str1")), normalInput) + assertJsonFormAndRestored(NullableStringDataHolder.serializer(), NullableStringDataHolder(null), nullInput) + } } diff --git a/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt b/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt index 22d87a72b7..4c1ef07670 100644 --- a/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt +++ b/formats/json/commonMain/src/kotlinx/serialization/json/JsonTransformingSerializer.kt @@ -52,7 +52,7 @@ import kotlinx.serialization.json.internal.* * Should be able to parse [JsonElement] from [transformDeserialize] function. * Usually, default [serializer] is sufficient. */ -public abstract class JsonTransformingSerializer( +public abstract class JsonTransformingSerializer( private val tSerializer: KSerializer ) : KSerializer { From b2ee9761b5a8521e71c47e98ac13650ab9c4a71b Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Wed, 22 Jan 2025 15:34:10 +0100 Subject: [PATCH 2/2] ~update klib dump --- formats/json/api/kotlinx-serialization-json.klib.api | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/formats/json/api/kotlinx-serialization-json.klib.api b/formats/json/api/kotlinx-serialization-json.klib.api index b91b902537..18c1078ee3 100644 --- a/formats/json/api/kotlinx-serialization-json.klib.api +++ b/formats/json/api/kotlinx-serialization-json.klib.api @@ -111,7 +111,7 @@ abstract class <#A: kotlin/Any> kotlinx.serialization.json/JsonContentPolymorphi final fun serialize(kotlinx.serialization.encoding/Encoder, #A) // kotlinx.serialization.json/JsonContentPolymorphicSerializer.serialize|serialize(kotlinx.serialization.encoding.Encoder;1:0){}[0] } -abstract class <#A: kotlin/Any> kotlinx.serialization.json/JsonTransformingSerializer : kotlinx.serialization/KSerializer<#A> { // kotlinx.serialization.json/JsonTransformingSerializer|null[0] +abstract class <#A: kotlin/Any?> kotlinx.serialization.json/JsonTransformingSerializer : kotlinx.serialization/KSerializer<#A> { // kotlinx.serialization.json/JsonTransformingSerializer|null[0] constructor (kotlinx.serialization/KSerializer<#A>) // kotlinx.serialization.json/JsonTransformingSerializer.|(kotlinx.serialization.KSerializer<1:0>){}[0] open val descriptor // kotlinx.serialization.json/JsonTransformingSerializer.descriptor|{}descriptor[0]