3

Why do I get error could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[A$A6.this.Bar] in the following code:

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])

It compiles with case class Bar(foo1: Foo), but Foo1 is subtype of Foo and I don't want to write duplicated encoder for Foo1 and Foo2. How to resolve this issue?

Nikita
  • 4,435
  • 3
  • 24
  • 44

1 Answers1

2

Try to define instances Decoder[Foo.Foo1] and Decoder[Foo.Foo2] (extract generic common part to avoid code duplication) and derive Decoder[Foo] using them.

  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]
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66