You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何将JSON数组或字符串反序列化为指定数据类?

问题分析

你遇到的JsonDecodingException核心原因是:ResponseList作为带value字段的数据类,默认序列化规则会期望解析{"value": [...]}结构的JSON对象,但接口返回的response是直接的JSON数组[...],两者结构不匹配导致解析失败。

解决方案

方案一:修正多态序列化器逻辑

调整ResponseSerializer,让它能直接将JSON数组解析为ResponseList,而不是依赖默认的对象序列化规则:

sealed class ResponseType

@Serializable
data class ResponseString(val value: String) : ResponseType()

@Serializable
data class ResponseList(val value: List<Response>) : ResponseType()

object ResponseSerializer : JsonContentPolymorphicSerializer<ResponseType>(ResponseType::class) {
    override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ResponseType> {
        return when (element) {
            is JsonPrimitive -> {
                if (element.isString) ResponseString.serializer()
                else throw IllegalArgumentException("不支持的原始类型")
            }
            is JsonArray -> object : DeserializationStrategy<ResponseList> {
                override val descriptor: SerialDescriptor = 
                    buildClassSerialDescriptor("ResponseList") {
                        element("value", ListSerializer(Response.serializer()).descriptor)
                    }

                override fun deserialize(decoder: Decoder): ResponseList {
                    require(decoder is JsonDecoder)
                    val responseList = decoder.json.decodeFromJsonElement<List<Response>>(element)
                    return ResponseList(responseList)
                }
            } as DeserializationStrategy<ResponseType>
            else -> throw IllegalArgumentException("不支持的JSON元素类型")
        }
    }
}

方案二:给ResponseList单独配置序列化器

给ResponseList指定自定义序列化器,让它直接和JSON数组做映射,无需外层包裹对象:

sealed class ResponseType

@Serializable
data class ResponseString(val value: String) : ResponseType()

@Serializable(with = ResponseListSerializer::class)
data class ResponseList(val value: List<Response>) : ResponseType()

object ResponseListSerializer : KSerializer<ResponseList> {
    private val listSerializer = ListSerializer(Response.serializer())

    override val descriptor: SerialDescriptor = listSerializer.descriptor

    override fun serialize(encoder: Encoder, value: ResponseList) {
        listSerializer.serialize(encoder, value.value)
    }

    override fun deserialize(decoder: Decoder): ResponseList {
        val list = listSerializer.deserialize(decoder)
        return ResponseList(list)
    }
}

// 原ResponseSerializer无需修改,保持原样即可
object ResponseSerializer : JsonContentPolymorphicSerializer<ResponseType>(ResponseType::class) {
    override fun selectDeserializer(element: JsonElement): DeserializationStrategy<ResponseType> =
        when {
            element is JsonPrimitive && element.isString -> ResponseString.serializer()
            else -> ResponseList.serializer()
        }
}

方案三:你的手动解析替代方案(可行)

如果觉得多态序列化器配置繁琐,你提到的直接用JsonElement接收再手动解析的方式完全可行,代码示例如下:

@Serializable
data class a(
    val status: String,
    val response: JsonElement
)

// 解析后处理逻辑
val apiResult = client.get<a>(/* 请求地址 */)
when (val responseElement = apiResult.response) {
    is JsonArray -> {
        val responseList = Json.decodeFromJsonElement<List<Response>>(responseElement)
        // 处理列表数据
    }
    is JsonPrimitive -> {
        if (responseElement.isString) {
            val responseStr = responseElement.content
            // 处理字符串数据
        }
    }
    else -> {
        // 处理其他意外类型
    }
}
额外注意事项
  • 建议在Json配置中开启ignoreUnknownKeys = true,避免c类存在未定义字段时解析失败:
    install(ContentNegotiation) {
        json(Json {
            ignoreUnknownKeys = true
            serializersModule = SerializersModule {
                polymorphic(ResponseType::class) {
                    subclass(ResponseString::class)
                    subclass(ResponseList::class)
                }
            }
        })
    }
    
  • Response类中用JsonPrimitive接收v1的写法是正确的,能兼容数字和字符串两种类型。

内容的提问来源于stack exchange,提问作者daispe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:15:12