Search code examples
kotlinserializationjson-deserializationkotlinx.serialization

Kotlinx Serialization - Custom serializer to ignore null value


Let's say I'm having a class like:

@Serializable
data class MyClass(
    @SerialName("a") val a: String?,
    @SerialName("b") val b: String
)

Assume the a is null and b's value is "b value", then Json.stringify(MyClass.serializer(), this) produces:

{ "a": null, "b": "b value" }

Basically if a is null, I wanted to get this:

{ "b": "b value" }

From some research I found this is currently not doable out of the box with Kotlinx Serialization so I was trying to build a custom serializer to explicitly ignore null value. I followed the guide from here but couldn't make a correct one.

Can someone please shed my some light? Thanks.


Solution

  • Try this (not tested, just based on adapting the example):

    @Serializable
    data class MyClass(val a: String?, val b: String) {
        @Serializer(forClass = MyClass::class)
            companion object : KSerializer<MyClass> {
            override val descriptor: SerialDescriptor = object : SerialClassDescImpl("MyClass") {
                init {
                    addElement("a")
                    addElement("b")
                }
            }
    
            override fun serialize(encoder: Encoder, obj: MyClass) {
                encoder.beginStructure(descriptor).run {
                    obj.a?.let { encodeStringElement(descriptor, 0, obj.a) }
                    encodeStringElement(descriptor, 1, obj.b)
                    endStructure(descriptor)
                }
            }
    
            override fun deserialize(decoder: Decoder): MyClass {
                var a: String? = null
                var b = ""
    
                decoder.beginStructure(descriptor).run {
                    loop@ while (true) {
                        when (val i = decodeElementIndex(descriptor)) {
                            CompositeDecoder.READ_DONE -> break@loop
                            0 -> a = decodeStringElement(descriptor, i)
                            1 -> b = decodeStringElement(descriptor, i)
                            else -> throw SerializationException("Unknown index $i")
                        }
                    }
                    endStructure(descriptor)
                }
    
                return MyClass(a, b)
            }
        }
    }