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

如何在Kotlin中解析answerData为多类型的JSON响应?

Kotlin 解析动态类型answerData字段方案

问题本质

直接将answerData声明为Any类型无法完成类型转换的核心原因是:JSON反序列化库默认会将未知结构的对象转为内部通用类型(如Gson的LinkedTreeMap、Moshi的MapJsonValue等),无法直接映射为业务侧定义的数据类,需要通过自定义反序列化逻辑适配动态类型场景。

核心实现思路

用密封类(Sealed Class)封装answerData所有可能的类型,配合JSON库的自定义反序列化适配器,先判断JSON节点的实际类型,再对应解析为密封类的子类实例。

具体实现步骤(以Gson为例,Moshi实现思路完全一致)

1. 定义密封类封装所有answerData可能的类型

sealed class AnswerData {
    // 对应answerData为null的场景
    object NullAnswer : AnswerData()

    // 对应单选选项对象场景
    data class SelectionOptionAnswer(
        val selectionOptionId: Int,
        val selectionOptionText: String?
    ) : AnswerData()

    // 对应关联关系对象场景
    data class AffiliationAnswer(
        val IsAffiliatedWithSeller: Boolean,
        val AffiliationDescription: String?
    ) : AnswerData()

    // 对应章节数组场景
    data class ChapterListAnswer(
        val items: List<Map<String, String>>
    ) : AnswerData()

    // 对应负债数组场景
    data class LiabilityListAnswer(
        val items: List<LiabilityItem>
    ) : AnswerData() {
        data class LiabilityItem(
            val liabilityTypeId: Int,
            val monthlyPayment: Int,
            val remainingMonth: Int,
            val liabilityName: String,
            val name: String
        )
    }
}

2. 实现自定义反序列化适配器

import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import java.lang.reflect.Type

class AnswerDataDeserializer : JsonDeserializer<AnswerData> {
    override fun deserialize(
        json: JsonElement?,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): AnswerData {
        return when {
            // 处理null场景
            json == null || json.isJsonNull -> AnswerData.NullAnswer
            // 处理对象场景
            json.isJsonObject -> {
                val jsonObj = json.asJsonObject
                when {
                    jsonObj.has("selectionOptionId") -> context!!.deserialize(
                    jsonObj,
                    AnswerData.SelectionOptionAnswer::class.java
                )
                    jsonObj.has("IsAffiliatedWithSeller") -> context!!.deserialize(
                    jsonObj,
                    AnswerData.AffiliationAnswer::class.java
                )
                    else -> AnswerData.NullAnswer
                }
            }
            // 处理数组场景
            json.isJsonArray -> {
                val jsonArr = json.asJsonArray
                if (jsonArr.isEmpty) return AnswerData.NullAnswer
                val firstItem = jsonArr[0].asJsonObject
                return when {
                    firstItem.has("liabilityTypeId") -> {
                    val list = jsonArr.map {
                        context!!.deserialize<AnswerData.LiabilityListAnswer.LiabilityItem>(
                            it,
                            AnswerData.LiabilityListAnswer.LiabilityItem::class.java
                        )
                    }
                    AnswerData.LiabilityListAnswer(list)
                }
                    else -> {
                    val list = jsonArr.map { item ->
                        item.asJsonObject.entrySet().associate { entry ->
                            entry.key to entry.value.asString
                        }
                    }
                    AnswerData.ChapterListAnswer(list)
                }
            }
            else -> AnswerData.NullAnswer
        }
    }
}

3. 注册适配器并定义外层响应结构

// 注册适配器到Gson实例
val gson = GsonBuilder()
    .registerTypeAdapter(AnswerData::class.java, AnswerDataDeserializer())
    .create()

// 外层响应数据类定义
data class ApiResponse(
    val status: String,
    val `data`: List<DataItem>
) {
    data class DataItem(
        val id: Int,
        val answerData: AnswerData
    )
}

4. 解析后使用示例

val response = gson.fromJson(jsonResponseStr, ApiResponse::class.java)
response.data.forEach { item ->
    when (val answer = item.answerData) {
        is AnswerData.NullAnswer -> // 处理空值逻辑
        is AnswerData.SelectionOptionAnswer -> // 处理单选选项逻辑
        is AnswerData.AffiliationAnswer -> // 处理关联关系逻辑
        is AnswerData.ChapterListAnswer -> // 处理章节列表逻辑
        is AnswerData.LiabilityListAnswer -> // 处理负债列表逻辑
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 12:27:08