Json-circe不能为密封性状的子类型导出编码器

时间:2018-04-10 16:18:07

标签: json scala circe

为什么我会收到错误could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[A$A6.this.Bar] 在以下代码中:

import io.circe.{Decoder, DecodingFailure, Encoder, HCursor, Json, ObjectEncoder}
import io.circe.generic.semiauto._
import io.circe.generic.semiauto._
import io.circe.syntax._
import io.circe.parser._

sealed trait Foo
object Foo {
  case class Foo1(foo1: String) extends Foo
  case class Foo2(foo2: String) extends Foo

}

case class Bar(foo1: Foo.Foo1)

implicit lazy val FooDecoder: Decoder[Foo] = new Decoder[Foo] {
  final def apply(c: HCursor): Decoder.Result[Foo] = {
    def decode(messageType: String, payload: Json): Decoder.Result[Foo] = messageType match {
      case "Foo1" => payload.as[Foo.Foo1](deriveDecoder[Foo.Foo1])
      case "Foo2" => payload.as[Foo.Foo2](deriveDecoder[Foo.Foo2])
    }

    for {
      messageType <- c.downField("type").as[String]
      payload <- c.downField("payload").focus.toRight(DecodingFailure("payload field is not present", Nil))
      in <- decode(messageType, payload)
    } yield in
  }
}

implicit lazy val barDecoder: Decoder[Bar] = deriveDecoder[Bar]

parse("""
  |{ "foo1": {
  |  "type" : "Foo1",
  |    "payload": {
  |      "foo1": "bar"
  |    }
  |  }
  |}
""".stripMargin)
  .flatMap(json => json.as[Bar])

它使用case class Bar(foo1: Foo)进行编译,但Foo1Foo的子类型,我不想为Foo1Foo2编写重复的编码器。如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

尝试定义实例Decoder[Foo.Foo1]Decoder[Foo.Foo2](提取通用公共部分以避免代码重复)并使用它们派生Decoder[Foo]

  def helper[T <: Foo : DerivedDecoder](s: String): Decoder[T] = new Decoder[T] {
    final def apply(c: HCursor): Decoder.Result[T] = {
      def decode(messageType: String, payload: Json): Decoder.Result[T] = messageType match {
        case _ if messageType == s => payload.as[T](deriveDecoder[T])
      }

      for {
        messageType <- c.downField("type").as[String]
        payload <- c.downField("payload").focus.toRight(DecodingFailure("payload field is not present", Nil))
        in <- decode(messageType, payload)
      } yield in
    }
  }

  implicit lazy val foo1Decoder: Decoder[Foo.Foo1] = helper[Foo.Foo1]("Foo1")
  implicit lazy val foo2Decoder: Decoder[Foo.Foo2] = helper[Foo.Foo2]("Foo2")
  implicit lazy val fooDecoder: Decoder[Foo] = deriveDecoder[Foo]
  implicit lazy val barDecoder: Decoder[Bar] = deriveDecoder[Bar]