Kotlinx 序列化 - 自定义序列化程序以忽略空值

Posted

技术标签:

【中文标题】Kotlinx 序列化 - 自定义序列化程序以忽略空值【英文标题】:Kotlinx Serialization - Custom serializer to ignore null value 【发布时间】:2020-01-23 04:06:24 【问题描述】:

假设我有这样的课程:

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

假设anull 并且b 的值是“b 值”,那么Json.stringify(MyClass.serializer(), this) 产生:

 "a": null, "b": "b value" 

基本上如果anull,我想得到这个:

 "b": "b value" 

通过一些研究,我发现目前无法通过 Kotlinx 序列化开箱即用,因此我试图构建一个自定义序列化程序以显式忽略 null 值。我按照here 的指南进行操作,但无法做出正确的指南。

有人可以帮我解释一下吗?谢谢。

【问题讨论】:

【参考方案1】:

JsonConfiguration 中使用encodeDefaults = false 属性,它不会序列化空值(或其他可选值)

【讨论】:

这仅在您想忽略并非总是如此的所有默认值时才有效。一个例子是 WooCommerce,其中有一个“variation_id”,如果它不存在,则不应将其作为订单项传递给订单,因此理想的路径是将其设置为 null,但 WooCommerce 不接受 null 作为价值。在这种情况下,更细粒度的控制可以说“如果尚未设置则忽略此值”或“如果它为空则忽略此值”。【参考方案2】:

试试这个(未测试,仅基于改编示例):

@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)
        
    

【讨论】:

【参考方案3】:

JsonConfiguration弃用,支持 Json 构建器,因为 kotlinx.serialization 1.0.0-RC 根据其changelog。

现在你必须像这样编写代码:

val json = Json  encodeDefaults = false 
val body = json.encodeToString(someSerializableObject)

【讨论】:

【参考方案4】:

你可以使用explicitNulls = false

示例:

@OptIn(ExperimentalSerializationApi::class)
val format = Json  explicitNulls = false 
    
@Serializable
data class Project(
    val name: String,
    val language: String,
    val version: String? = "1.3.0",
    val website: String?,
)
    
fun main() 
    val data = Project("kotlinx.serialization", "Kotlin", null, null)
    val json = format.encodeToString(data)
    println(json) // "name":"kotlinx.serialization","language":"Kotlin"

https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#explicit-nulls

【讨论】:

以上是关于Kotlinx 序列化 - 自定义序列化程序以忽略空值的主要内容,如果未能解决你的问题,请参考以下文章

使用 kotlinx 序列化响应中的自定义对象列表

kotlinx.serialization - 使用自定义 DateSerializer 将 ArrayList<Date> 序列化为数据类变量

@SerialInfo - 如何使用 Kotlinx 序列化管理用户定义的串行注释?

在 kotlinx.serialization 中编码/解码 JSON“字符串”

没有@Serializable 的数据类的自定义序列化程序

IJSRuntime 忽略服务器端 Blazor 项目中的自定义 json 序列化程序