用于子类类型的Circe编码器/解码器

时间:2017-06-23 15:02:12

标签: scala circe

鉴于以下ADT

sealed abstract class GroupRepository(val `type`: String) {
  def name: String
  def repositories: Seq[String]
  def blobstore: String
}
case class DockerGroup(name: String, repositories: Seq[String], blobstore: String = "default") extends GroupRepository("docker")
case class BowerGroup(name: String, repositories: Seq[String], blobstore: String = "default") extends GroupRepository("bower")
case class MavenGroup(name: String, repositories: Seq[String], blobstore: String = "default") extends GroupRepository("maven")

其中值type用于解码要实例化的实例。

如何自动(或半自动)派生编码器和解码器,我得到以下行为:

> println(MavenGroup("test", Seq("a", "b")).asJson.spaces2)
{
  "type" : "maven",
  "name" : "test",
  "repositories" : [
     "a",
     "b"
  ],
  "blobstore" : "default"
}
> println((MavenGroup("test", Seq("a", "b")): GroupRepository).asJson.spaces2)
{
  "type" : "maven",
  "name" : "test",
  "repositories" : [
     "a",
     "b"
  ],
  "blobstore" : "default"
}

传统的做法

object GroupRepository {
  implicit val encoder = semiauto.deriveEncoder[GroupRepository]
  implicit val decoder = semiauto.deriveDecoder[GroupRepository]
}

在两个方面失败:

  • 它不会序列化值type
  • 不允许MavenGroup("test", Seq("a", "b")).asJson。它仅允许MavenGroup首次投放到GroupRepository的第二个备选方案。

我能提出的最佳解决方案是:

object GroupRepository {
  implicit def encoder[T <: GroupRepository]: Encoder[T] = Encoder.instance(a => Json.obj(
    "type" -> Json.fromString(a.`type`),
    "name" -> Json.fromString(a.name),
    "repositories" -> Json.fromValues(a.repositories.map(Json.fromString)),
    "blobstore" -> Json.fromString(a.blobstore)
  ))
  implicit def decoder[T <: GroupRepository]: Decoder[T] = Decoder.instance(c =>
    c.downField("type").as[String].flatMap {
      case "docker" => c.as[DockerGroup](semiauto.deriveDecoder[DockerGroup])
      case "bower" => c.as[BowerGroup](semiauto.deriveDecoder[BowerGroup])
      case "maven" => c.as[MavenGroup](semiauto.deriveDecoder[MavenGroup])
    }.right.map(_.asInstanceOf[T])
  )
}

但是有几个缺点:

  • 手动指定编码器。
  • 每个子类型的解码器都没有被缓存,因为必须明确地传递编码器。

0 个答案:

没有答案