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

