Kotlinx 将 JSON Array 序列化为数据类

Posted

技术标签:

【中文标题】Kotlinx 将 JSON Array 序列化为数据类【英文标题】:Kotlinx serialization of JSON Array to data class 【发布时间】:2021-12-21 11:20:14 【问题描述】:

对于我的 android 应用,我尝试使用 Kotlinx 序列化来解析网络响应。网络响应是来自Kraken 的 WebSocket Payload,看起来像一个 JSON 数组,其中包含没有键的元素。我想为此响应创建一个数据类并分配缺少的键。网络响应如下所示:

 [
  324,
  
    "a": [
      "65534.00000",
      8,
      "8.45840938"
    ],
    "b": [
      "65533.90000",
      0,
      "0.00352122"
    ],
    "c": [
      "65533.90000",
      "0.00458332"
    ],
    "v": [
      "2282.41761567",
      "3048.01677262"
    ],
    "p": [
      "65297.21555",
      "64608.96127"
    ],
    "t": [
      27317,
      38224
    ],
    "l": [
      "63319.60000",
      "61810.00000"
    ],
    "h": [
      "66420.00000",
      "66420.00000"
    ],
    "o": [
      "63319.60000",
      "61962.00000"
    ]
  ,
  "ticker",
  "XBT/USD"
]

【问题讨论】:

这是什么反应?我在这里看不到任何模式。你能解释一下吗?你还想要什么样的数据类?你能给出一些大纲吗? 这是来自 Kraken 的 WebSocket 的有效负载:Kraken 我有一个回调函数,用于推送更新的数据。我之前尝试的是构建 Payload。 【参考方案1】:

对于 JSON 数组

[
  "id": 324,
  "items": 
    "a": [
      "65534.00000",
      8,
      "8.45840938"
    ],
    "b": [
      "65533.90000",
      0,
      "0.00352122"
    ],
    "c": [
      "65533.90000",
      "0.00458332"
    ],
    "v": [
      "2282.41761567",
      "3048.01677262"
    ],
    "p": [
      "65297.21555",
      "64608.96127"
    ],
    "t": [
      27317,
      38224
    ],
    "l": [
      "63319.60000",
      "61810.00000"
    ],
    "h": [
      "66420.00000",
      "66420.00000"
    ],
    "o": [
      "63319.60000",
      "61962.00000"
    ]
  ,
  "unit" : "ticker",
  "code" : "XBT/USD"
]

Kotlin 数据类将是

import com.google.gson.annotations.SerializedName

   
data class Example (

   @SerializedName("id") var id : Int,
   @SerializedName("items") var items : Items,
   @SerializedName("unit") var unit : String,
   @SerializedName("code") var code : String

)

但是,您的响应看起来不像 JSON 数组,其格式应为:

[,,]

你的回复是一个普通的数组形式:

[,,,]

【讨论】:

感谢您的回答!我认为它是一个 JSON 数组,除了 Objects 之外还包含 Int 和 String 类型的值。如果在您的示例中存在值的键,则可以在数据类中分配一个名称。但在我的回复中,钥匙不见了。【参考方案2】:

最后我最终将有效负载解码为 JsonArray 并手动将其内容提供给我的数据类。

这是我的数据类:

@Serializable
data class Ticker(
    var channelID : String,
    var channelName : String,
    var pair : String,
    var ticker : TickerData,
)

@Serializable
data class TickerData(
    @SerialName("a")
    val ask: Ask,

    @SerialName("b")
    val bid: Bid,

    @SerialName("c")
    val close: Close,

    @SerialName("h")
    val volume: Volume,

    @SerialName("l")
    val volumeWeightedAveragePrice: VolumeWeightedAveragePrice,

    @SerialName("o")
    val numberOfTrades: NumberOfTrades,

    @SerialName("p")
    val lowPrice: LowPrice,

    @SerialName("t")
    val highPrice: HighPrice,

    @SerialName("v")
    val openPrice: OpenPrice,
)

@Serializable
data class Ask(
      var price: String,
      var wholeLotVolume: Int,
      var lotVolume: String,
)

@Serializable
data class Bid(
    var price: String,
    var wholeLotVolume: Int,
    var lotVolume: String,
)

@Serializable
data class Close(
    var price: String,
    var lotVolume: String,
)

@Serializable
data class Volume(
    var today: String,
    var last24Hours: String,
) 
 
@Serializable
data class VolumeWeightedAveragePrice(
    var today: String,
    var last24Hours: String,
)

@Serializable
data class NumberOfTrades(
    var today: String,
    var last24Hours: String,
)

@Serializable
data class LowPrice(
    var today: String,
    var last24Hours: String,
)

@Serializable
data class HighPrice(
    var today: String,
    var last24Hours: String,
)

@Serializable
data class OpenPrice(
    var today: String,
    var last24Hours: String,
)

这是我的有效负载解析器:

class KrakenApiWebSocketPayload(val json: Json) 
    fun getTicker(response:String): Ticker 
        val tickerArray : JsonArray = json.decodeFromString(response)
        val tickerObject : JsonObject = tickerArray[1].jsonObject

        val ask : JsonArray = tickerObject.get("a")!!.jsonArray
        val bid : JsonArray = tickerObject.get("b")!!.jsonArray
        val close : JsonArray = tickerObject.get("c")!!.jsonArray
        val volume : JsonArray = tickerObject.get("h")!!.jsonArray
        val volumeWeightedAveragePrice : JsonArray = tickerObject.get("l")!!.jsonArray
        val numberOfTrades : JsonArray = tickerObject.get("o")!!.jsonArray
        val lowPrice : JsonArray = tickerObject.get("p")!!.jsonArray
        val highPrice : JsonArray = tickerObject.get("t")!!.jsonArray
        val openPrice : JsonArray = tickerObject.get("v")!!.jsonArray

        return Ticker(tickerArray[0].toString(),tickerArray[2].toString(),tickerArray[3].toString(),
                    TickerData(
                        Ask(ask[0].toString(),ask[1].toString().toInt(),ask[2].toString()),
                        Bid(bid[0].toString(),bid[1].toString().toInt(),bid[2].toString()),
                        Close(close[0].toString(),close[1].toString()),
                        Volume(volume[0].toString(),volume[1].toString()),
                        VolumeWeightedAveragePrice(volumeWeightedAveragePrice[0].toString(),volumeWeightedAveragePrice[1].toString()),
                        NumberOfTrades(numberOfTrades[0].toString(),numberOfTrades[1].toString()),
                        LowPrice(lowPrice[0].toString(),lowPrice[1].toString()),
                        HighPrice(highPrice[0].toString(),highPrice[1].toString()),
                        OpenPrice(openPrice[0].toString(),openPrice[1].toString())

                    )
        )
       
 

【讨论】:

以上是关于Kotlinx 将 JSON Array 序列化为数据类的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 kotlinx 序列化将值数组反序列化为集合

在 kotlinx.serialization 中编码/解码 JSON“字符串”

kotlinx.serialization - 使用自定义 DateSerializer 将 ArrayList<Date> 序列化为数据类变量

如何使用 kotlinx.serialization 将库类序列化为 Protobuf?

将表单序列化为json对象

将表单序列化为json对象