Suppose I have a ADT in Scala:
sealed trait Base
case class Foo(i: Int) extends Base
case class Baz(x: String) extends Base
I want to encode values of this type into the JSON that looks like the following:
{ "Foo": { "i": 10000 }}
{ "Baz": { "x": "abc" }}
Which luckily is exactly the encoding circe's generic derivation provides!
scala> import io.circe.generic.auto._, io.circe.syntax._
import io.circe.generic.auto._
import io.circe.syntax._
scala> val foo: Base = Foo(10000)
foo: Base = Foo(10000)
scala> val baz: Base = Baz("abc")
baz: Base = Baz(abc)
scala> foo.asJson.noSpaces
res0: String = {"Foo":{"i":10000}}
scala> baz.asJson.noSpaces
res1: String = {"Baz":{"x":"abc"}}
The problem is that the encoder circe uses depends on the static type of the expression we're encoding. This means that if we try to decode one of the case classes directly, we lose the discriminator:
scala> Foo(10000).asJson.noSpaces
res2: String = {"i":10000}
scala> Baz("abc").asJson.noSpaces
res3: String = {"x":"abc"}
…but I want the Base
encoding even when the static type is Foo
. I know I can define explicit instances for all of the case classes, but in some cases I might have a lot of them, and I don't want to have to enumerate them.
(Note that this is a question that's come up a few times—e.g. here.)