【问题标题】:Optional field vs null value in kotlinx.serializationkotlinx.serialization 中的可选字段与空值
【发布时间】:2021-05-25 19:44:11
【问题描述】:

如何区分 {data: null}{}kotlinx.serialization 中反序列化 JSON 时?

@Serializable
class MyClass(val data: String?)

【问题讨论】:

  • 您的意思是您正在接收这种 JSON,并且您想在 Kotlin 中以一种可以区分的方式表示它?
  • 您的代码示例甚至不会在第二种情况下运行,因为data 不是可选的。您需要设置一个默认值,如果data 不存在并且这就是您的答案,则将使用该默认值。
  • @Joffrey,这正是我想要的
  • 前段时间我正在研究完全相同的问题,不幸的是,如果没有一些 hack,kotlinx.serialization 并不能真正支持它:-( 你总是可以编写自己的序列化程序或执行以下操作: const val UNDEFINED = "<random>" 然后将你的道具声明为:val data: String? = UNDEFINED
  • 无论如何你都可以使用parseToJsonElement 方法——它会为这些JSON返回不同的对象

标签: json kotlin kotlinx.serialization


【解决方案1】:

您需要一个自定义设置器和一个私有布尔字段来指示该字段值是否被触摸。所以像:

@Serializable
class MyClass {
    private var isDataTouched = false

    val data: String
        set(value) {        
            field = value
            isDataTouched = true
        }
}

注意,不能在默认构造函数中定义字段。

【讨论】:

    【解决方案2】:

    您可以利用polymorphismJsonContentPolymorphicSerializer 来区分您要反序列化的响应类型:

    @Serializable(with = MyResponseSerializer::class)
    sealed class MyResponse
    
    @Serializable
    class MyEmptyClass : MyResponse()
    
    @Serializable
    class MyClass(val data: String?) : MyResponse()
    
    // this serializer is reponsible for determining what class we will receive
    // by inspecting json structure
    object MyResponseSerializer : JsonContentPolymorphicSerializer<MyResponse>(MyResponse::class) {
        override fun selectDeserializer(element: JsonElement) = when {
            "data" in element.jsonObject -> MyClass.serializer()
            else -> MyEmptyClass.serializer()
        }
    }
    

    之后使用MyResponse 类进行反序列化,您将收到MyEmptyClassMyClass

    val e = Json.decodeFromString<MyResponse>("""{}""")             // returns MyEmptyClass object
    val o = Json.decodeFromString<MyResponse>("""{"data": null}""") // returns MyClass object
    
    println(Json.encodeToString(e)) // {}
    println(Json.encodeToString(o)) // {"data": null}
    
    // since sealed class is the parent we can have exhaustive when:
    when(e) {
        is MyClass -> TODO("handle response with data")
        is MyEmptyClass -> TODO("handle empty response")
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-07-29
      • 1970-01-01
      • 2023-03-07
      • 2019-04-11
      • 1970-01-01
      • 2020-11-13
      • 2013-06-11
      • 1970-01-01
      相关资源
      最近更新 更多