【问题标题】:(De)Serializing class hierarchy (from)to Json with Scala Play json lib(De) 使用 Scala Play json lib 将类层次结构 (from) 序列化为 Json
【发布时间】:2016-07-01 14:53:03
【问题描述】:

有没有更好的方法来做到这一点?我想避免 Mammal 伴侣对象的读写方法上的模式匹配。

OTOH 我怀疑 shapeless 的可扩展记录在这里会有所帮助,但我不确定如何使用它。谁能告诉我如何使用 shapeless 来完成?

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]

【问题讨论】:

    标签: json scala serialization deserialization shapeless


    【解决方案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"}
    

    【讨论】:

    • 我对使用类型级、通用编程或元编程而不是显式反射的解决方案感兴趣。谢谢
    猜你喜欢
    • 2012-05-06
    • 1970-01-01
    • 2021-05-06
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 2011-11-08
    • 1970-01-01
    • 2016-08-03
    相关资源
    最近更新 更多