Как читать массив массивов JSON со смешанными значениями в Retrofit 2?

Я пытаюсь прочитать следующие данные из API:

[
    [
        1724180400000,
        "59191.45000000",
        "59597.28000000",
        "59137.78000000",
        "59511.99000000",
        "544.56764000",
        1724183999999,
        "32351755.73378980",
        51002,
        "290.20494000",
        "17241827.16012430",
        "0"
    ],
    [
        1724184000000,
        "59512.00000000",
        "59722.72000000",
        "59421.38000000",
        "59589.07000000",
        "301.58055000",
        1724187599999,
        "17968010.37382020",
        23563,
        "169.48375000",
        "10099057.30721750",
        "0"
    ]
]

Но Retrofit ожидает, что ответ JSON будет начинаться с «{» вместо «[».

Я попробовал сериализовать данные со следующими зависимостями:

implementation(libs.retrofit)
implementation(libs.retrofit2.kotlinx.serialization.converter)
implementation(libs.okhttp)
implementation(libs.kotlinx.serialization.json)

Когда я говорю Retrofit ожидать список со списками, он сообщает, что «Сериализатор для класса «Любой» не найден». Как сериализовать этот тип ответа только с помощью массивов, содержащих смешанные типы (String и Int)?


50
2

Ответы:

Решено

Если тип не имеет значения, вы можете просто использовать тип String.

@GET("test")
fun test(): Call<List<List<String>>>

Если тип имеет значение, вы можете использовать JsonPrimitive.

@GET("test")
fun test(): Call<List<List<JsonPrimitive>>>

После того, как вы получили данные, вы можете проанализировать их List<List<Any>> вот так.

val result: List<List<JsonPrimitive>> = response.body()!!

val parsedResult: List<List<Any>> = result.map { innerItem ->
    innerItem.map {
         if (it.isNumber) it.asInt
         else it.asString
    }
}

println(parsedResult)

Ответы в этой теме очень помогли понять и решить проблему. В своем приложении для Android я реализовал такое решение:

В сервисе API (интерфейс Retrofit 2)

@GET("klines.json")
suspend fun getKlines(): List<List<JsonPrimitive>>

В сетевом репозитории извлеките и преобразуйте rawJson в мой собственный класс Kline.

override suspend fun getKlines(): List<Kline> {
    val rawJson = apiService.getKlines()
    return rawJson.map { data ->
        Kline(
            timestamp = data[0].long,
            open = data[1].double,
            high = data[2].double,
            low = data[3].double,
            close = data[4].double,
            volume = data[5].double,
            closeTime = data[6].long,
            quoteAssetVolume = data[7].double,
            numberOfTrades = data[8].int,
            takerBuyBaseAssetVolume = data[9].double,
            takerBuyQuoteAssetVolume = data[10].double
        )
    }
}

Тип Call в моем сценарии не понадобился, поскольку функции вызываются из области сопрограммы.

Результат rawJson в logcat:

[[1724151600000, "60716.01000000", "60734.91000000", "60401.90000000", "60518.82000000", "1086.55870000", 1724155199999, "65807817.60717790", 58639, "538.35193000", "32602791.90598670", "0"], [...] ] 

Эта реализация работает для меня, но приветствуются лучшие решения!