Retrofit2+Kotlinx Serialization反序列化遇JsonDecodingException求助
问题解决:Retrofit2 + Kotlinx Serialization 反序列化异常
核心错误分析
- JSON结构与数据模型不匹配:JSON响应中
data是数组([]),但你的MarsPhoto类中data字段定义为单个Eta对象,这会直接导致解码时期望对象却读取到数组,触发JsonDecodingException。 - 类型不匹配:JSON里的
service_type是整数类型(如1),但Eta类中该字段定义为String,后续会引发类型转换错误。 - 异常信息中的
EOF是结构不匹配导致解析中断后出现的附加提示,核心问题还是模型结构错误。
修正后的代码模型
根模型类
@Serializable data class MarsPhoto( val type: String = "", // 返回数据对应的API标识 val version: String = "", // 返回JSON的版本号 val generated_timestamp: String = "", // 响应初始生成时间戳(缓存前) val data: List<Eta> // 修改为List<Eta>,匹配JSON数组结构 )
ETA数据类
@Serializable data class Eta( val co: String = "KMB", // 公交公司 val route: String = "", // 公交线路编号 val dir: String = "", // 线路方向 val service_type: Int = 0, // 修改为Int类型,对应JSON中的整数 val seq: Int = 0, // 站点序号 val dest_tc: String = "", // 繁体中文目的地 val dest_sc: String = "", // 简体中文目的地 val dest_en: String = "", // 英文目的地 val eta_seq: Int = 0, // ETA序号 val eta: String = "-", // 下一班次时间戳 val rmk_tc: String = "", // 繁体中文备注 val rmk_sc: String = "", // 简体中文备注 val rmk_en: String = "", // 英文备注 val data_timestamp: String = "" // 数据初始生成时间戳 )
额外优化建议
如果希望更规范地处理时间戳,可以引入kotlinx serialization的时间序列化扩展,将时间字段类型改为Instant:
- 添加依赖(build.gradle.kts):
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.2") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
- 自定义序列化器并修改字段:
import kotlinx.datetime.Instant import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder object InstantAsStringSerializer : kotlinx.serialization.KSerializer<Instant> { override val descriptor: SerialDescriptor = String.serializer().descriptor override fun deserialize(decoder: Decoder): Instant { return Instant.parse(decoder.decodeString()) } override fun serialize(encoder: Encoder, value: Instant) { encoder.encodeString(value.toString()) } } // 在数据类中使用示例: @Serializable(with = InstantAsStringSerializer::class) val generated_timestamp: Instant = Instant.DISTANT_PAST
内容的提问来源于stack exchange,提问作者Dwill James
相关产品推荐
相关产品推荐

