Как декодировать массив, содержащий json, с помощью 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
. Как видно, эти значения находятся в массиве.
Я подозреваю, что Цирцея хочет расшифровать
List[data]
но я не хочу создавать
case class DataInfo(list: List[Data])
это просто не кажется правильным.
1 ответ
Вы только что пропустили
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)
}
Небольшая рекомендация:
Я бы посоветовал вам определить базовый декодер, он должен просто декодировать из
data
объект:
{
"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))