【问题标题】:Play 2.1 Json serialization for traits?为特征播放 2.1 Json 序列化?
【发布时间】:2012-12-18 04:48:31
【问题描述】:

我有这个:

package models

import play.api.libs.json._
import play.api.libs.functional.syntax._

object ModelWrites {
    implicit val tmoWrites= Json.writes[TestModelObject]
    implicit val ihWrites = Json.writes[IntHolder]
}

case class TestModelObject(s1:String, s2:String)

case class IntHolder(i1:Int, i2:Int)

trait HasInts {
    val ints: List[IntHolder]
}

当我这样做时:

scala> val tmo = new TestModelObject("hello", "world") with HasInts {
  val ints = List(IntHolder(1,2), IntHolder(3,4))
}

scala> Json.toJson(tmo)
res0: play.api.libs.json.JsValue = {"s1":"hello","s2":"world"}

如何隐式序列化混合的 val 'ints'?喜欢:

scala> val someInts = List(IntHolder(8,9), IntHolder(10,11))
someInts: List[models.IntHolder] = List(IntHolder(8,9), IntHolder(10,11))

scala> Json.toJson(someInts)
res1: play.api.libs.json.JsValue = [{"i1":8,"i2":9},{"i1":10,"i2":11}]

注意:如果我尝试:implicit val hasIntsWrites = Json.writes[HasInts] 我(预期?)得到:

[error] Models.scala:10: No unapply function found
[error]     implicit val hasIntsWrites = Json.writes[HasInts]
[error]                                             ^

【问题讨论】:

    标签: json scala playframework playframework-2.1


    【解决方案1】:

    您将无法在此处直接使用the experimental "Inception" feature (Json.writes[...]),因为这仅适用于案例类。但是,您可以在 Inception 可以 提供的 Writes 实例的基础上构建,只需很少的样板即可完成您想要的工作。

    请注意,我忽略了这样的问题:在实例化这样的案例类时混合特征是否是一个好主意——它可能不是——但我在这里给出的方法也适用于更一般的情况.

    首先是类和导入(这里没有变化):

    case class TestModelObject(s1: String, s2: String)
    case class IntHolder(i1: Int, i2: Int)
    trait HasInts { val ints: List[IntHolder] }
    
    import play.api.libs.json._
    import play.api.libs.functional.syntax._
    

    现在我们需要将所有优先级较低的实例放入一个特征中,以确保编译器会选择正确的实例,因为TestModelObject with HasIntsTestModelObjectHasInts 的子类型:

    trait LowPriorityWritesInstances {
      implicit val tmoWrites = Json.writes[TestModelObject]
      implicit val ihWrites = Json.writes[IntHolder]
    
      implicit object hiWrites extends OWrites[HasInts] {
        def writes(hi: HasInts) = Json.obj("ints" -> hi.ints)
      }
    }
    

    现在是重头戏:

    object WritesInstances extends LowPriorityWritesInstances {
      implicit val tmowhiWrites = new Writes[TestModelObject with HasInts] {
        def writes(o: TestModelObject with HasInts) =
          tmoWrites.writes(o) ++ implicitly[OWrites[HasInts]].writes(o)
      }
    }
    

    我们完成了:

    scala> import WritesInstances._
    import WritesInstances._
    
    scala> val tmo = new TestModelObject("hello", "world") with HasInts {
         |   val ints = List(IntHolder(1, 2), IntHolder(3, 4))
         | }
    
    scala> println(Json.toJson(tmo))
    {"s1":"hello","s2":"world","ints":[{"i1":1,"i2":2},{"i1":3,"i2":4}]}
    

    根据需要。

    【讨论】:

    • 太棒了。正是我想要的。谢谢! “请注意,我忽略了这样的问题:在实例化这样的案例类时混合特征是否是一个好主意——它可能不是”如果你愿意解释的话,我会全力以赴 :)
    • 现在我在猜测自己。 “Case-to-case”继承长期以来一直不鼓励,并且在 2.10 中被禁止,但是您在这里所做的(从 case 类匿名继承)可能不会导致任何相同的问题。因此,您可能可以忽略这一点。当我有几分钟的时间检查更多细节时,我会尝试更新答案。
    猜你喜欢
    • 2012-12-18
    • 2016-07-26
    • 2013-04-29
    • 1970-01-01
    • 2016-06-22
    • 2011-10-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多