Json-circe 无法为密封特征的子类型派生编码器

Json-circe can't derive encoder for subtype of sealed trait

为什么会出现错误 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 编写重复的编码器.如何解决这个问题?

尝试定义实例 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]