鉴于以下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])
)
}
但是有几个缺点: