【问题标题】:Play 2.1 Json serialization of traits玩2.1 特征的Json序列化
【发布时间】:2024-05-02 13:45:02
【问题描述】:

Play 2.1 (Json.format[...]) 中的实验性“Inception”功能仅适用于案例类(请参阅here)。如何为特征编写隐含的自定义格式。我有以下构造:

sealed trait Plan {
  def id: String
  def name: String
  def apps: Int
  def users: Int
  def testruns: Int
  def price: Int
  def prio: Int
}

以及以下扩展特征计划的案例类。

case class Start(
                  id: String = "start",
                  name: String = "Start",
                  apps: Int = 1,
                  users: Int = 1,
                  testruns: Int = 10,
                  price: Int = 99,
                  prio: Int = 30) extends Plan

case class Pro(
                id: String = "pro",
                name: String = "Pro",
                apps: Int = 2,
                users: Int = 5,
                testruns: Int = 25,
                price: Int = 299,
                prio: Int = 20) extends Plan

case class Premium(
                    id: String = "premium",
                    name: String = "Premium",
                    apps: Int = -1,
                    users: Int = -1,
                    testruns: Int = -1,
                    price: Int = 799,
                    prio: Int = 10) extends Plan

现在我需要在 Plan 伴随对象中编写我的自定义隐式格式 val。我试过了:

object Plan {
  implicit val planFormats = (
    (__ \ "id").format[String] and
    (__ \ "name").format[String] and
    (__ \ "apps").format[Int] and
    (__ \ "users").format[Int] and
    (__ \ "testruns").format[Int] and
    (__ \ "price").format[Int] and
    (__ \ "prio").format[Int]
  )(Plan.apply, unlift(Plan.unapply))
}

但是,特征没有 apply 或 unapply 方法。在 Play 2.1 中为 json 序列化提供隐式 val 的正确方法是什么?

【问题讨论】:

    标签: json scala playframework-2.0


    【解决方案1】:

    您只需提供您自己的函数,从给定值创建一个新实例。

    本质上是作为工厂的特征的伴随对象。

    object Plan {
      def apply(id: String, name: String, ...) = id match {
        case "pro" => new Pro(id, name, ...)
        ...
      }
    
      def unapply(p: Person): Option[(String, String, ...)] = ...
    }
    

    【讨论】:

    • 谢谢,这是有道理的。在这个例子中 unapply 方法会是什么样子?抱歉,我还是 Scala 的新手。
    • unapply 正好相反——从案例类创建一个元组。只需在 REPL 中尝试一下,例如Start.unapply _ 创建了一个从 Start 到参数 n 元组的 Option 的函数。
    【解决方案2】:

    你为什么要使用 Traits 和实现案例类?

    为什么不使用类的实例,例如:

    case class Plan (
      id: String,
      name: String,
      apps: Int,
      users: Int,
      testruns: Int,
      price: Int,
      prio: Int
    )
    
    val start = new Plan("start", "Start", 1, 1, 10, 99, 30)
    val pro = new Plan("pro", "Pro", 2, 5, 25, 299, 20)
    val premium = new Plan("premium", "Premium", -1, -1, -1, 799, 10)
    

    然后,您可以保留您的 Json 格式化程序:

    object Plan {
      implicit val planFormats = (
        (__ \ "id").format[String] and
        (__ \ "name").format[String] and
        (__ \ "apps").format[Int] and
        (__ \ "users").format[Int] and
        (__ \ "testruns").format[Int] and
        (__ \ "price").format[Int] and
        (__ \ "prio").format[Int]
      )(Plan.apply, unlift(Plan.unapply))
    }
    

    【讨论】:

    • 在这种情况下它有效!您只需将“案例类计划”上的大括号更改为括号。感谢您的解决方案。如果 Plan 是一个案例类,我什至可以再次使用“implicit val planFormats = Json.format[Plan]”,而不是编写我的自定义格式。但是,我仍然对如何为特征编写隐含的自定义格式感兴趣。