【问题标题】:CIRCE: How to decode a json model with disjunction in a field typeCIRCE:如何使用字段类型中的析取来解码 json 模型
【发布时间】:2019-12-27 06:33:06
【问题描述】:

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

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

我正在使用 circe 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]

【问题讨论】:

  • 我能够通过使用 List[Double] 解决问题,工作代码是 case class Report(id:Int, latlng:List[Double])。

标签: json scala circe


【解决方案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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-18
    • 2019-09-26
    • 1970-01-01
    • 2018-02-14
    • 2018-03-10
    • 2018-05-03
    • 2019-05-31
    • 2023-03-09
    相关资源
    最近更新 更多