如何使用 Circe 解码包含 json 的数组
How to decode array containing json with Circe
我有我的 circe 解码器,如下所示。我相信我的 Sentiment Decoder 工作正常,所以不会在下面包含它。
case class CryptoData(value: String, valueClassification: Sentiment)
implicit val decoder: Decoder[CryptoData] = Decoder.instance { json =>
for {
value <- json.downField("data").get[String]("value")
valueClassification <- json.downField("data").get[Sentiment]("value_classification")
} yield CryptoData(value, valueClassification)
}
我的Json看起来像这样
{
"name" : "Fear and Greed Index",
"data" : [
{
"value" : "31",
"value_classification" : "Fear",
"timestamp" : "1631318400",
"time_until_update" : "54330"
}
],
"metadata" : {
"error" : null
}
}
我只想要 value
和 value_classification
。可以看出,这些值位于一个数组中。
我怀疑 Circe 正在寻找解码 List[data]
但我不想创建 case class DataInfo(list: List[Data])
它只是感觉不对。
您刚刚错过了将 data
解析为对象数组的 downArray
调用。工作解码器:
implicit val cryptoDecoder: Decoder[CryptoData] = Decoder.instance { json =>
val data = json.downField("data").downArray
for {
value <- data.get[String]("value")
valueClassification <- data.get[Sentiment]("value_classification")
} yield CryptoData(value, valueClassification)
}
小建议:
我建议您为 CryptoData
定义一个基本解码器,它应该只从 data
对象解码 CryptoData
:
{
"value" : "31",
"value_classification" : "Fear",
"timestamp" : "1631318400",
"time_until_update" : "54330"
}
至:
CryptoData("31", Fear)
如果您有一些扩展 JSON,您可以使用一些自定义解析器和解析对象向下移动到实际的 CryptoData
字段。
完整代码:
import io.circe
import io.circe.Decoder
import io.circe.parser._
trait Sentiment
object Sentiment {
case object Fear extends Sentiment
implicit val sentimentDecoder: Decoder[Sentiment] = Decoder.decodeString.map {
case "Fear" => Fear
}
}
case class CryptoData(value: String, valueClassification: Sentiment)
object CryptoData {
implicit val cryptoDecoder: Decoder[CryptoData] = Decoder.instance { json =>
for {
value <- json.downField("value").as[String]
valueClassification <- json.downField("value_classification").as[Sentiment]
} yield CryptoData(value, valueClassification)
}
def decodeRaw(extendedObject: String): Either[circe.Error, Array[CryptoData]] =
parse(extendedObject).flatMap(json => json.hcursor.downField("data").as[Array[CryptoData]])
}
测试:
val extendedJson =
"""
|{
| "name" : "Fear and Greed Index",
| "data" : [
| {
| "value" : "31",
| "value_classification" : "Fear",
| "timestamp" : "1631318400",
| "time_until_update" : "54330"
| }
| ],
| "metadata" : {
| "error" : null
| }
|}
|""".stripMargin
// here should be Array
val result: Either[circe.Error, Array[CryptoData]] = CryptoData.decodeRaw(extendedJson)
// Right(CryptoData(31,Fear))
println(result.map(_.mkString(", ")))
val cryptoDataJson =
"""
|{
| "value" : "31",
| "value_classification" : "Fear",
| "timestamp" : "1631318400",
| "time_until_update" : "54330"
| }
|""".stripMargin
// Right(CryptoData(31,Fear))
println(decode[CryptoData](cryptoDataJson))
我有我的 circe 解码器,如下所示。我相信我的 Sentiment Decoder 工作正常,所以不会在下面包含它。
case class CryptoData(value: String, valueClassification: Sentiment)
implicit val decoder: Decoder[CryptoData] = Decoder.instance { json =>
for {
value <- json.downField("data").get[String]("value")
valueClassification <- json.downField("data").get[Sentiment]("value_classification")
} yield CryptoData(value, valueClassification)
}
我的Json看起来像这样
{
"name" : "Fear and Greed Index",
"data" : [
{
"value" : "31",
"value_classification" : "Fear",
"timestamp" : "1631318400",
"time_until_update" : "54330"
}
],
"metadata" : {
"error" : null
}
}
我只想要 value
和 value_classification
。可以看出,这些值位于一个数组中。
我怀疑 Circe 正在寻找解码 List[data]
但我不想创建 case class DataInfo(list: List[Data])
它只是感觉不对。
您刚刚错过了将 data
解析为对象数组的 downArray
调用。工作解码器:
implicit val cryptoDecoder: Decoder[CryptoData] = Decoder.instance { json =>
val data = json.downField("data").downArray
for {
value <- data.get[String]("value")
valueClassification <- data.get[Sentiment]("value_classification")
} yield CryptoData(value, valueClassification)
}
小建议:
我建议您为 CryptoData
定义一个基本解码器,它应该只从 data
对象解码 CryptoData
:
{
"value" : "31",
"value_classification" : "Fear",
"timestamp" : "1631318400",
"time_until_update" : "54330"
}
至:
CryptoData("31", Fear)
如果您有一些扩展 JSON,您可以使用一些自定义解析器和解析对象向下移动到实际的 CryptoData
字段。
完整代码:
import io.circe
import io.circe.Decoder
import io.circe.parser._
trait Sentiment
object Sentiment {
case object Fear extends Sentiment
implicit val sentimentDecoder: Decoder[Sentiment] = Decoder.decodeString.map {
case "Fear" => Fear
}
}
case class CryptoData(value: String, valueClassification: Sentiment)
object CryptoData {
implicit val cryptoDecoder: Decoder[CryptoData] = Decoder.instance { json =>
for {
value <- json.downField("value").as[String]
valueClassification <- json.downField("value_classification").as[Sentiment]
} yield CryptoData(value, valueClassification)
}
def decodeRaw(extendedObject: String): Either[circe.Error, Array[CryptoData]] =
parse(extendedObject).flatMap(json => json.hcursor.downField("data").as[Array[CryptoData]])
}
测试:
val extendedJson =
"""
|{
| "name" : "Fear and Greed Index",
| "data" : [
| {
| "value" : "31",
| "value_classification" : "Fear",
| "timestamp" : "1631318400",
| "time_until_update" : "54330"
| }
| ],
| "metadata" : {
| "error" : null
| }
|}
|""".stripMargin
// here should be Array
val result: Either[circe.Error, Array[CryptoData]] = CryptoData.decodeRaw(extendedJson)
// Right(CryptoData(31,Fear))
println(result.map(_.mkString(", ")))
val cryptoDataJson =
"""
|{
| "value" : "31",
| "value_classification" : "Fear",
| "timestamp" : "1631318400",
| "time_until_update" : "54330"
| }
|""".stripMargin
// Right(CryptoData(31,Fear))
println(decode[CryptoData](cryptoDataJson))