Kotlinx 序列化,避免在其他数据类型上崩溃

Posted

技术标签:

【中文标题】Kotlinx 序列化,避免在其他数据类型上崩溃【英文标题】:Kotlinx Serialization, avoid crashes on other datatype 【发布时间】:2020-02-02 09:18:33 【问题描述】:

我在应用程序中使用外部 API,而反序列化是使用 Kotlinx 序列化包完成的,当 api 结果是多个值的 Int 数组和单个值的原始 int 时,我遇到了问题。我怎样才能避免在这个过程中崩溃。有没有更好的方法来避免崩溃或创建数据类

例如:

import kotlinx.serialization.Serializable

@Serializable

data class Bookings (val slots: List<Int>)

当插槽具有单值时 API 返回 slots: 1 当 slot 有多个值时 API 返回 slots: [1,2,3,4]

【问题讨论】:

【参考方案1】:

可以使用自定义序列化器来完成:

import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonInput
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.int

@Serializable(with = BookingsSerializer::class)
data class Bookings(val slots: List<Int>)

@Serializer(forClass = Bookings::class)
object BookingsSerializer : KSerializer<Bookings> 
    override fun deserialize(decoder: Decoder): Bookings 
        val json = (decoder as JsonInput).decodeJson().jsonObject
        return Bookings(parseSlots(json))
    

    private fun parseSlots(json: JsonObject): List<Int> 
        val slotsJson = json["slots"] ?: return emptyList()
        return try 
            slotsJson.jsonArray.content.map  it.int 
         catch (e: Exception) 
            listOf(slotsJson.int)
        
    


@ImplicitReflectionSerializer
fun main() 
    val json = """"slots": 1"""
    val result = Json.parse<Bookings>(json)
    println(result) // prints Bookings(slots=[1])

【讨论】:

除了自定义序列化器还有其他方法 至少我不知道他们:) 类名好像过时了【参考方案2】:

我更新了@Andrei 对 2021 年的回答,因为自 2019 年以来类和方法名称发生了一些变化:

import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlinx.serialization.encoding.Decoder

@Serializable(with = BookingsSerializer::class)
data class Bookings(val slots: List<Int>)

@Serializer(forClass = Bookings::class)
object BookingsSerializer : KSerializer<Bookings> 
    override fun deserialize(decoder: Decoder): Bookings 
        val json = (decoder as JsonDecoder).decodeJsonElement().jsonObject
        return Bookings(parseSlots(json))
    

    private fun parseSlots(json: JsonObject): List<Int> 
        val slotsJson = json["slots"] ?: return emptyList()
        return try 
            slotsJson.jsonArray.map  it.jsonPrimitive.int 
         catch (e: Exception) 
            listOf(slotsJson.jsonPrimitive.int)
        
    


val json = """"slots": 1"""
val result = Json.decodeFromString<Bookings>(json)
println(result.toString()) // prints Bookings(slots=[1])

【讨论】:

以上是关于Kotlinx 序列化,避免在其他数据类型上崩溃的主要内容,如果未能解决你的问题,请参考以下文章

使用 kotlinx.serialization 库反序列化具有不同值类型的 JSON 数组

IgnoreUnknownKeys 仅适用于 Kotlinx 和 Ktor 的一种类型

Kotlinx 序列化:如何绕过 reified typeargs 进行反序列化?

Kotlinx 将 JSON Array 序列化为数据类

Kotlinx 序列化 - 如何为未知字段名编写数据类

如何使用 kotlinx 序列化将值数组反序列化为集合