簡體   English   中英

ADT Json序列化/反序列化

[英]ADT Json serialization/deserialization

嘗試使用Circe來序列化和反序列化Scala中的代數數據類型我嘗試了以下示例,遵循文檔和Web上的一些示例:

  sealed trait StringData
  case class Data2(f1: String, f2: String) extends StringData
  case class Data3(f1: String, f2: String, f3: String) extends StringData

  object StringData {
    // ===> does not work, always picks Data2 type
    implicit val decodeData: Decoder[Data] = Decoder[OptionsData].map[Data](identity).or(Decoder[TextData].map[Data](identity))

    implicit val encodeData: Encoder[StringData] = Encoder.instance {
      case d2 @ Data2( _,_) => d2.asJson
      case d3 @ Data3( _, _, _) => d3.asJson
    }

    def toJson(s: StringData): String = s.asJson.noSpaces
    def fromJson(s: String): Either[Error, StringData] = decode[StringData](s)
  }

  "Inheritance ADT with identical fields" should "serialize and deserialize with Circe" in {
    val d2 = Data2("a", "b")
    val d3 = Data3("1", "2", "3")

    val jd2 = StringData.toJson(d2)
    val jd3 = StringData.toJson(d3)

    val d2Decoded = StringData.fromJson(jd2)
    val d3Decoded = StringData.fromJson(jd3)

    d2Decoded.right.get should equal(d2)
    d3Decoded.right.get should equal(d3)

    println("")
  }

問題是d3Decoded的類型始終是Data2類型而不是所需的Data3

我想出的解決方案是用這個替換解碼器:

    implicit val decodeData: Decoder[StringData] = Decoder.instance { c =>
      c.downField("f3").as[String] match {
        case m: Either[DecodingFailure, String] if m.isLeft => c.as[Data2]
        case m: Either[DecodingFailure, String] if m.isRight => c.as[Data3]
      }
    }

在我看來,這是一個非常特別的解決方案。 在傑克遜,有可能將類型添加到Json。 我想知道我是否以正確的方式使用Circe,或者這是否真的是這樣做的。 任何評論都非常歡迎。

嘗試使用此處記錄的鑒別器

import io.circe.generic.extras.auto._
import io.circe.generic.extras.Configuration
import io.circe.parser.decode

implicit val genDevConfig: Configuration =
  Configuration.default.withDiscriminator("what_am_i")

sealed trait StringData
case class Data2(f1: String, f2: String) extends StringData
case class Data3(f1: String, f2: String, f3: String) extends StringData

decode[StringData]("""{ "f1": "foo", "f2": "bar", "f3": "qux", "what_am_i": "Data3" }""")

哪個輸出

res0: Either[io.circe.Error,StringData] = Right(Data3(foo,bar,qux)

哪里

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM