(De)使用Scala Play json lib将类层次结构(从)序列化为Json

时间:2016-03-15 22:39:09

标签: json scala serialization deserialization shapeless

有更好的方法吗?我想避免在Mammal伴侣对象的读写方法上进行模式匹配。

OTOH我怀疑无形的可扩展记录可以在这里提供帮助,但我不确定如何使用它。有谁能告诉我如何使用无形的方式来完成它?

import play.api.libs.json._

object X {

  trait Animal {
    val category: String
    val subcategory: String
  }

  sealed trait Mammal extends Animal {
    override val category = Mammal.name
  }

  object Man {
    implicit val format = Json.format[Man]
    val name = "Man"
  }

  case class Man(weight: Int) extends Mammal {
    override val subcategory = Man.name
  }

  object Whale {
    implicit val format = Json.format[Whale]
    val name = "Whale"
  }

  case class Whale(weight: Int) extends Mammal {
    override val subcategory = Whale.name
  }

  object Mammal {
    val name = "Mammal"

    implicit val format: Format[Mammal] = new Format[Mammal] {

      def writes(m: Mammal): JsValue = {
        val json = m match {
          case x: Man => Json.toJson(x)(Man.format)
          case x: Whale => Json.toJson(x)(Whale.format)
        }
        json.as[JsObject] + ("category" -> JsString(m.category)) + ("subcategory" -> JsString(m.subcategory))
      }

      def reads(json: JsValue): JsResult[Mammal] = {
        (json \ "subcategory").as[String] match {
          case Man.name => json.validate[Man]
          case Whale.name => json.validate[Whale]
          case unknown => JsError(s"Unknown subcategory '$unknown'")
        }
      }
    }
  }
}

import X._

val man: Mammal = Man(100)
val whale: Mammal = Whale(1000)

val json = Json.toJson(man)
val read = json.validate[Mammal]

1 个答案:

答案 0 :(得分:1)

代码

为了写作,我创建了一个通用方法。

  def writes(m: Mammal) = {
    val mapTest = (Map[String, Any]() /: m.getClass.getDeclaredFields) {(a, f) =>
                      f.setAccessible(true)
                      a + (f.getName -> f.get(m))
                   } - "$outer"
    Json.obj(mapTest.map{case (s, o) =>
      val ret:(String, JsValueWrapper) = o match {
        case _:String => s -> JsString(o.asInstanceOf[String])
        case _:Int => s -> JsNumber(o.asInstanceOf[Int])
        case _ => s -> JsString("")
      }
      ret
    }.toSeq:_*)
  }

输出

json: play.api.libs.json.JsValue = {"weight":100,"subcategory":"Man","category":"Mammal"}