Skip to content

Instantly share code, notes, and snippets.

@ostronom
Last active July 12, 2016 22:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ostronom/fdbbf6e038b6fe4cd84a3caefc4f1ce7 to your computer and use it in GitHub Desktop.
Save ostronom/fdbbf6e038b6fe4cd84a3caefc4f1ce7 to your computer and use it in GitHub Desktop.
uPickle derive.key-like behaviour for circe
import cats.data.Xor
import io.circe.parser._
import io.circe._
import io.circe.generic.encoding.DerivedObjectEncoder
import io.circe.syntax._
import io.circe.generic.semiauto._
sealed trait X
case class A(i: Int) extends X
case class B(i: Int) extends X
object Main extends App {
def genEncoder[T: DerivedObjectEncoder](tag: String) = new Encoder[T] {
val derived = deriveEncoder[T]
override def apply(u: T) = derived(u).mapObject(o => o.add("$type", tag.asJson))
}
def genDecoder[T](discriminator: PartialFunction[String, Decoder[_ <: T]]) = new Decoder[T] {
override def apply(c: HCursor) = c.downField("$type").as[String] match {
case Xor.Right(tpe) if discriminator.isDefinedAt(tpe) =>
discriminator(tpe)(c)
case _ => Xor.Left(DecodingFailure(s"Cannot deduce decoder", c.history))
}
}
implicit val encoderA: Encoder[A] = genEncoder[A]("A")
implicit val encoderB: Encoder[B] = genEncoder[B]("B")
implicit val decoderA: Decoder[A] = deriveDecoder[A]
implicit val decoderB: Decoder[B] = deriveDecoder[B]
implicit val decoderC: Decoder[X] = genDecoder[X] {
case "A" => decoderA
case "B" => decoderB
}
val as = A(10).asJson.noSpaces
val bs = B(10).asJson.noSpaces
println(as, bs, parse(as).map(_.as[X]), parse(bs).map(_.as[X]))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment