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

如何在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线数据字段),可以将内层数组映射为数据类,通过自定义序列化器完成数组到数据类的转换。

  1. 定义数据类与自定义序列化器
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) {
        // 若无需序列化发送数据,可空实现
    }
}
  1. 定义Retrofit接口
interface ApiService {
    @GET("your-api-endpoint")
    suspend fun fetchKLineData(): List<KLineData>
}
  1. 配置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>>接收响应,再手动解析每个元素:

  1. 定义Retrofit接口
import kotlinx.serialization.json.JsonElement
import retrofit2.http.GET

interface ApiService {
    @GET("your-api-endpoint")
    suspend fun fetchKLineData(): List<List<JsonElement>>
}
  1. 解析响应数据
val responseData = apiService.fetchKLineData()
responseData.forEach { innerArray ->
    val timestamp = innerArray[0].jsonPrimitive.long
    val openPrice = innerArray[1].jsonPrimitive.content
    // 按索引解析其他字段
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:17:37