Json-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), но Foo1 является подтипом Foo, и я не хочу писать дублирующий кодировщик для Foo1 и Foo2. Как решить эту проблему?


person Nikita    schedule 10.04.2018    source источник


Ответы (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]
person Dmytro Mitin    schedule 10.04.2018