如何在Retrofit 2中读取含混合类型的JSON数组数组?
解决Retrofit序列化混合类型嵌套数组的问题
问题分析
API返回嵌套数组结构,内层数组包含Long、String、Int等混合类型元素。直接使用List<List<Any>>会触发Serializer for class 'Any' is not found错误——因为Kotlinx Serialization无法为无具体类型的Any生成序列化器;而“期望JSON以'{'开头”的错误,通常是Retrofit返回类型配置错误导致的,Retrofit本身支持数组类型响应。
解决方案
方案一:自定义数据类+序列化器(推荐)
内层数组的元素位置固定(对应标准K线数据字段),可以将内层数组映射为数据类,通过自定义序列化器完成数组到数据类的转换。
- 定义数据类与自定义序列化器
import kotlinx.serialization.Serializable import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.descriptors.buildClassSerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.JsonDecoder import kotlinx.serialization.json.jsonArray @Serializable(with = KLineDataSerializer::class) data class KLineData( val timestamp: Long, val open: String, val high: String, val low: String, val close: String, val volume: String, val closeTimestamp: Long, val quoteVolume: String, val tradeCount: Int, val takerBuyBaseVolume: String, val takerBuyQuoteVolume: String, val ignore: String ) object KLineDataSerializer : kotlinx.serialization.KSerializer<KLineData> { override val descriptor: SerialDescriptor = buildClassSerialDescriptor("KLineData") override fun deserialize(decoder: Decoder): KLineData { val jsonArray = (decoder as JsonDecoder).decodeJsonElement().jsonArray return KLineData( timestamp = jsonArray[0].toString().toLong(), open = jsonArray[1].toString(), high = jsonArray[2].toString(), low = jsonArray[3].toString(), close = jsonArray[4].toString(), volume = jsonArray[5].toString(), closeTimestamp = jsonArray[6].toString().toLong(), quoteVolume = jsonArray[7].toString(), tradeCount = jsonArray[8].toString().toInt(), takerBuyBaseVolume = jsonArray[9].toString(), takerBuyQuoteVolume = jsonArray[10].toString(), ignore = jsonArray[11].toString() ) } override fun serialize(encoder: Encoder, value: KLineData) { // 若无需序列化发送数据,可空实现 } }
- 定义Retrofit接口
interface ApiService { @GET("your-api-endpoint") suspend fun fetchKLineData(): List<KLineData> }
- 配置Retrofit
import okhttp3.MediaType.Companion.toMediaType import retrofit2.Retrofit import retrofit2.converter.kotlinx.serialization.asConverterFactory import kotlinx.serialization.json.Json val retrofit = Retrofit.Builder() .baseUrl("your-base-url") .addConverterFactory(Json.asConverterFactory("application/json".toMediaType())) .build() val apiService = retrofit.create(ApiService::class.java)
方案二:使用JsonElement手动解析
如果不想定义数据类,可以用List<List<JsonElement>>接收响应,再手动解析每个元素:
- 定义Retrofit接口
import kotlinx.serialization.json.JsonElement import retrofit2.http.GET interface ApiService { @GET("your-api-endpoint") suspend fun fetchKLineData(): List<List<JsonElement>> }
- 解析响应数据
val responseData = apiService.fetchKLineData() responseData.forEach { innerArray -> val timestamp = innerArray[0].jsonPrimitive.long val openPrice = innerArray[1].jsonPrimitive.content // 按索引解析其他字段 }
内容的提问来源于stack exchange,提问作者Marc
相关产品推荐
相关产品推荐

