电路:如何使用字段类型中的析取值解码json模型

时间:2019-08-22 00:56:25

标签: json scala circe

我正在开发的应用程序必须从数据源解码json,对于给定字段,该数据源可能返回List [String]或List [Double]。我想将此json解码为case类,以便我可以处理数据。

[{
    "id": 123,
    "latlng": ["-12.777", "18.776"]
}, {
    "id": 123,
    "latlng": [-12.777, 18.776]
}]

Im使用大约0.11.1

目前我的案例类看起来像

case class Report(id:Int, latlng:Either[List[String],List[Double]])

和我的解码代码

 decode[List[Report]](testData) 

我收到错误

DecodingFailure at [0].latlng: [A, B]Either[A, B]

1 个答案:

答案 0 :(得分:1)

听起来您已经有了适合您的解决方案。我找到了解决您原始问题的方法。它不是很优雅,但是可以工作。也许有一个更优雅的解决方案,涉及到Cats库中的Validated monad,但是我对Cats库并不十分熟悉,无法以这种方式编写它。

import io.circe._
import io.circe.parser._

object Main {

  def main(args: Array[String]) = {
    val testData =
      """
        |[{
        |    "id": 123,
        |    "latling": ["-12.777", "18.776"]
        |}, {
        |    "id": 123,
        |    "latling": [-12.777, 18.776]
        |}]
      """.stripMargin

    println(decode[List[Report]](testData))

  }

  case class Report(id: Int, latling: Either[List[String],List[Double]])

  object Report {
    implicit val reportDecoder: Decoder[Report] = new Decoder[Report] {
      override def apply(c: HCursor): Decoder.Result[Report] = {
        val stringAttempt = for {
          id <- c.downField("id").as[Int]
          latlingString <- c.downField("latling").as[List[String]]
        } yield Report(id, Left(latlingString))

        val doubleAttempt = for {
          id <- c.downField("id").as[Int]
          latlingDouble <- c.downField("latling").as[List[Double]]
        } yield Report(id, Right(latlingDouble))

        stringAttempt match {
          case Right(stringValue) => Right(stringValue)
          case Left(stringFailure) => doubleAttempt
        }
      }
    }
  }
}

您可以通过

启动sbt来运行
sbt

并运行

runMain Main

这是我的build.sbt文件:

name := "stackoverflow20190821"

version := "0.1"

scalaVersion := "2.12.0"

val circeVersion = "0.11.1"

libraryDependencies ++= Seq(
  "io.circe" %% "circe-core",
  "io.circe" %% "circe-generic",
  "io.circe" %% "circe-parser"
).map(_ % circeVersion)