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
相关产品推荐
相关产品推荐

