在 Scala Play 中对自定义类列表进行读取和写入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34437520/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 07:53:15  来源:igfitidea点击:

Making Reads and Writes in Scala Play for lists of custom classes

jsonscalaplayframework

提问by Will

So I have two classes in my project

所以我的项目中有两个类

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

and

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

I'm trying to make reads and writes properties for Order but I get a compiler error saying:

我正在尝试为 Order 设置读取和写入属性,但我收到一个编译器错误说:

"No unapply or unapplySeq function found"

“未找到 unapply 或 unapplySeq 函数”

In my controller I have the following:

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

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]]

The code works for itemReadsand itemWritesbut not for the bottom two. Can anyone tell me where I'm going wrong, I'm new to Play framework.

代码工作的itemReadsitemWrites而不是底部的两个。谁能告诉我哪里出错了,我是 Play 框架的新手。

Thank you for your time.

感谢您的时间。

回答by Jonik

The "No unapply or unapplySeq function found" error is caused by these two:

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

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

Just throw them away. As Ende said, Play knows how to deal with lists.

把它们扔掉就行了。正如恩德所说,Play 知道如何处理列表。

But you need Readsand Writesfor Ordertoo! And since you do both reading and writing, it's simplest to define a Format, a mix of the Readsand Writestraits. This should work:

但是,你需要ReadsWritesOrder呢!并且由于您同时进行阅读和写作,因此定义 a FormatReadsWrites特征的混合是最简单的。这应该有效:

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]
}

Above, the ordering is significant; Itemand the companion object must come before Order.

以上,排序很重要Item并且伴随对象必须在Order.

So, once you have all the implicit converters needed, the key is to make them properly visiblein the controllers. The above is one solution, but there are other ways, as I learned after trying to do something similar.

所以,一旦你拥有了所有需要的隐式转换器,关键是让它们在控制器中正确可见。以上是一种解决方案,但还有其他方法,正如我在尝试做类似的事情后学到的。

回答by Ende Neu

You don't actually need to define those two implicits, play already knows how to deal with a list:

您实际上不需要定义这两个隐式,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@478fdbc9

scala>   implicit val itemWrites = Json.writes[Item]
itemWrites: play.api.libs.json.OWrites[Item] = play.api.libs.json.OWrites$$anon@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":""}]}

The error you see probably happens because play uses the unapply method to construct the macro expansion for your read/write and Listis an abstract class, play-json needs concrete type to make the macro work.

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

回答by nattyddubbs

This works:

这有效:

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))

This also allows you to customize the naming for your JSON object. Below is an example of the serialization in action.

这还允许您自定义 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)))

I'd also recommend using formatinstead of readand writeif you are doing symmetrical serialization / deserialization.

我也建议使用format,而不是readwrite你正在做的对称序列化/反序列化。