Предположим, что у меня есть ADT:
sealed trait Event
case class Foo(i: Int) extends Event
case class Bar(s: String) extends Event
case class Baz(c: Char) extends Event
case class Qux(values: List[String]) extends Event
Генерированный по умолчанию вывод для экземпляра Decoder[Event]
в circe предполагает, что входной JSON будет включать объект-оболочку, который указывает, какой класс класса представлен:
scala> import io.circe.generic.auto._, io.circe.parser.decode, io.circe.syntax._
import io.circe.generic.auto._
import io.circe.parser.decode
import io.circe.syntax._
scala> decode[Event]("""{ "i": 1000 }""")
res0: Either[io.circe.Error,Event] = Left(DecodingFailure(CNil, List()))
scala> decode[Event]("""{ "Foo": { "i": 1000 }}""")
res1: Either[io.circe.Error,Event] = Right(Foo(1000))
scala> (Foo(100): Event).asJson.noSpaces
res2: String = {"Foo":{"i":100}}
Это поведение означает, что нам не нужно беспокоиться о двусмысленности, если два или более класса классов имеют одинаковые имена членов, но это не всегда то, что мы хотим - иногда мы знаем, что развернутая кодировка будет однозначной, или мы хотим устранить указывая порядок, в котором каждый класс должен быть опробован, или нам просто все равно.
Как я могу кодировать и декодировать мой Event
ADT без оболочки (желательно без необходимости писать мои кодеры и декодеры с нуля)?
(Этот вопрос довольно часто встречается - см., например, эту дискуссию с Игорем Мазором о Гиттере сегодня утром.)