【问题标题】:Making Reads and Writes in Scala Play for lists of custom classes在 Scala Play 中对自定义类列表进行读取和写入
【发布时间】:2015-12-23 14:12:19
【问题描述】:

所以我的项目中有两个类

case class Item(id: Int, name: String)

case class Order(id: Int, items: List[Item])

我正在尝试为 Order 进行读写属性,但我收到编译器错误提示:

“未找到 unapply 或 unapplySeq 函数”

在我的控制器中,我有以下内容:

implicit val itemReads = Json.reads[Item]
implicit val itemWrites = Json.writes[Item]
implicit val listItemReads = Json.reads[List[Item]]
implicit val listItemWrites = Json.writes[List[Item]]

该代码适用于itemReadsitemWrites,但不适用于底部两个。谁能告诉我哪里出错了,我是 Play 框架的新手。

感谢您的宝贵时间。

【问题讨论】:

    标签: json scala playframework


    【解决方案1】:

    No unapply or unapplySeq function found”错误是由这两个引起的:

    implicit val listItemReads = Json.reads[List[Item]]
    implicit val listItemWrites = Json.writes[List[Item]]
    

    把它们扔掉。 As Ende said,Play 知道如何处理列表。

    但是对于Order,您也需要ReadsWrites!而且由于您同时进行阅读和写作,因此定义Format 是最简单的,它是ReadsWrites 特征的混合。这应该有效:

    case class Item(id: Int, name: String)
    
    object Item {
      implicit val format = Json.format[Item]
    }
    
    case class Order(id: Int, items: List[Item])
    
    object Order {
      implicit val format = Json.format[Order]
    }
    

    以上,ordering is significantItem 和伴随对象必须在 Order 之前。

    因此,一旦您拥有所需的所有隐式转换器,关键是让它们在控制器中正确可见。以上是一种解决方案,但还有其他方法,正如我在trying to do something similar之后了解到的那样。

    【讨论】:

      【解决方案2】:

      你实际上不需要定义这两个隐式,play 已经知道如何处理一个列表:

      scala> import play.api.libs.json._ 
      import play.api.libs.json._
      
      scala>   case class Item(id: Int, name: String)
      defined class Item
      
      scala>   case class Order(id: Int, items: List[Item])
      defined class Order
      
      scala>   implicit val itemReads = Json.reads[Item]
      itemReads: play.api.libs.json.Reads[Item] = play.api.libs.json.Reads$$anon$8@478fdbc9
      
      scala>   implicit val itemWrites = Json.writes[Item]
      itemWrites: play.api.libs.json.OWrites[Item] = play.api.libs.json.OWrites$$anon$2@26de09b8
      
      scala>   Json.toJson(List(Item(1, ""), Item(2, "")))
      res0: play.api.libs.json.JsValue = [{"id":1,"name":""},{"id":2,"name":""}]
      
      scala>   Json.toJson(Order(10, List(Item(1, ""), Item(2, ""))))
      res1: play.api.libs.json.JsValue = {"id":10,"items":[{"id":1,"name":""},{"id":2,"name":""}]}
      

      您看到的错误可能是因为 play 使用 unapply 方法为您的读/写构造宏扩展,而 List 是一个抽象类,play-json 需要具体类型才能使宏工作。

      【讨论】:

      • 你是对的,Json.reads[List[Item]]Json.writes[List[Item]] 不是必需的;这些会导致“未找到 unapply 或 unapplySeq 函数”错误。但是,List 工作得很好,不需要具体类型。我认为可以通过使用以下方法之一使隐式转换器正确可见来解决 OP 的情况:stackoverflow.com/q/34615571/56285
      【解决方案3】:

      这行得通:

      case class Item(id: Int, name: String)
      
      case class Order(id: Int, items: List[Item])
      
      implicit val itemFormat = Json.format[Item]
      implicit val orderFormat: Format[Order] = (
        (JsPath \ "id").format[Int] and
          (JsPath \ "items").format[JsArray].inmap(
            (v: JsArray) => v.value.map(v => v.as[Item]).toList,
            (l: List[Item]) => JsArray(l.map(item => Json.toJson(item)))
          )
        )(Order.apply, unlift(Order.unapply))
      

      这还允许您自定义 JSON 对象的命名。下面是一个实际的序列化示例。

      Json.toJson(Order(1, List(Item(2, "Item 2"))))
      res0: play.api.libs.json.JsValue = {"id":1,"items":[{"id":2,"name":"Item 2"}]}
      
      Json.parse(
        """
          |{"id":1,"items":[{"id":2,"name":"Item 2"}]}
        """.stripMargin).as[Order]
      res1: Order = Order(1,List(Item(2,Item 2)))
      

      如果您要进行对称序列化/反序列化,我还建议使用format 而不是readwrite

      【讨论】:

      • @Will:虽然这可行,但幸运的是,它方式比必要的复杂!正如 Ende 所指出的,Play 已经知道如何处理列表。试试这个:stackoverflow.com/a/34618829/56285
      猜你喜欢
      • 2015-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-11
      相关资源
      最近更新 更多