如何编写Kotlin数据类正确解析含动态checklists字段的JSON响应
核心问题分析
- 服务端返回的
checklists字段是动态键的映射结构,键为分类名称(如"Frequência Cardíaca"),值为对应的检查项对象,你定义的固定属性的CheckLists类完全不符合该结构 - 报错
Expected BEGIN_OBJECT but was BEGIN_ARRAY说明服务端逻辑不一致:存在检查项时返回对象{},无检查项时返回空数组[],类型不统一导致解析失败
修正后的数据类代码
直接删除无用的CheckLists类,调整EvoData的checklists字段类型为动态Map,优先用Kotlin数据类简化写法:
import com.google.gson.annotations.Expose import com.google.gson.annotations.SerializedName import com.google.gson.annotations.JsonAdapter // 根响应类 data class Evolution( @SerializedName("message") @Expose val message: String? = null, @SerializedName("data") @Expose val data: List<EvoData>? = null ) // data数组的元素类 data class EvoData( @SerializedName("id") @Expose val id: Int? = null, @SerializedName("tipo_evolucao_id") @Expose val tipoEvolucaoId: Int? = null, @SerializedName("tipo_evolucao") @Expose val tipoEvolucao: String? = null, @SerializedName("data_hora") @Expose val dataHora: String? = null, @SerializedName("responsavel") @Expose val responsavel: String? = null, @SerializedName("evolucao") @Expose val evolucao: String? = null, // 核心修改:用Map接收动态键的checklists,添加自定义适配器兼容数组/对象两种格式 @SerializedName("checklists") @Expose @JsonAdapter(ChecklistTypeAdapter::class) val checklists: Map<String, Checklist>? = null ) // 单个检查分类类 data class Checklist( @SerializedName("label") @Expose val label: String? = null, @SerializedName("itens") @Expose val itens: List<Itens>? = null ) // 检查项类 data class Itens( @SerializedName("pergunta") @Expose val pergunta: String? = null, @SerializedName("resposta") @Expose val resposta: String? = null )
兼容类型不一致的TypeAdapter实现
新增ChecklistTypeAdapter类,处理服务端返回空数组的异常情况:
import com.google.gson.Gson import com.google.gson.TypeAdapter import com.google.gson.stream.JsonReader import com.google.gson.stream.JsonToken import com.google.gson.stream.JsonWriter class ChecklistTypeAdapter : TypeAdapter<Map<String, Checklist>>() { private val gson = Gson() override fun write(out: JsonWriter, value: Map<String, Checklist>?) { // 序列化逻辑按需实现,不需要可以留空 gson.toJson(value, object : com.google.gson.reflect.TypeToken<Map<String, Checklist>>() {}.type, out) } override fun read(reader: JsonReader): Map<String, Checklist>? { return when (reader.peek()) { // 如果是对象类型正常解析 JsonToken.BEGIN_OBJECT -> gson.fromJson(reader, object : com.google.gson.reflect.TypeToken<Map<String, Checklist>>() {}.type) // 如果是数组类型(服务端无数据返回[])直接返回空Map JsonToken.BEGIN_ARRAY -> { reader.beginArray() reader.endArray() emptyMap() } else -> null } } }
修改后即可正常解析所有返回结果,动态键会自动存入Map的key中,对应检查项存入value。
内容的提问来源于stack exchange,提问作者João Gabriel
相关产品推荐
相关产品推荐

