scala 在 Play 中将 Seq 映射到 JSON
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24498740/
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
Mapping Seq to JSON in Play
提问by Erik Pragt
I'm trying to map a Scala case class to JSON using Play 2.x. This works for simple versions of the case class, but not when there's a Seq or List of objects involved: then I get 'no implicit format' and 'no unapply function found' errors.
我正在尝试使用 Play 2.x 将 Scala 案例类映射到 JSON。这适用于 case 类的简单版本,但不适用于涉及 Seq 或 List 的对象:然后我得到“无隐式格式”和“未找到未应用函数”错误。
The code I'm using for this is the following:
我为此使用的代码如下:
case class Book(title: String, authors: Seq[Author])
case class Author(name: String)
I've used the Json.formatmacro to generate the Reads and Writes for this:
我已经使用Json.format宏为此生成读取和写入:
implicit val bookFormat = Json.format[Book]
implicit val authorFormat = Json.format[Author]
But now when I'm compiling my code, I get the following error:
但是现在当我编译我的代码时,我收到以下错误:
Error:(25, 40) Play 2 Compiler:
/Users/erikp/Userfiles/projects/play/booksearch/app/models/user.scala:25: No implicit format for Seq[models.Author] available.
implicit val bookFormat = Json.format[Book]
^
Without the Seq it works nicely, but with the Seq, it fails. I tried adding implicit val authorsFormat = Json.format[Seq[Author]]to the implicit converters, but that has no effect.
没有 Seq 它可以很好地工作,但是有了 Seq,它就失败了。我尝试添加implicit val authorsFormat = Json.format[Seq[Author]]到隐式转换器,但这没有效果。
采纳答案by Fernando Correia
Define the formatters respecting their dependency order, for each class in the graph that needs to be serialized.
为图中需要序列化的每个类定义符合其依赖顺序的格式化程序。
Formatting Bookrequires formatting Author, so define the Authorformatter before the Bookformatter.
格式化Book需要格式化Author,所以在Author格式化之前定义Book格式化。
For example, with this Models.scalafile:
例如,使用此Models.scala文件:
package models
import play.api.libs.json._
case class Book(title: String, authors: Seq[Author])
case class Author(name: String)
object Formatters {
implicit val authorFormat = Json.format[Author]
implicit val bookFormat = Json.format[Book]
}
and this JsonExample.scalafile:
和这个JsonExample.scala文件:
package controllers
import models._
import models.Formatters._
import play.api.mvc._
import play.api.libs.json._
object JsonExample extends Controller {
def listBooks = Action {
val books = Seq(
Book("Book One", Seq(Author("Author One"))),
Book("Book Two", Seq(Author("Author One"), Author("Author Two")))
)
val json = Json.toJson(books)
Ok(json)
}
}
a request to listBookswill produce this result:
listBooks将产生以下结果的请求:
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 133
<
[{"title":"Book One","authors":[{"name":"Author One"}]},{"title":"Book Two","authors":[{"name":"Author One"},{"name":"Author Two"}]}]
For more advanced formatting, including partial serialization to avoid having to declare formatters for classes that should not be serialized, see JSON Reads/Writes/Format Combinators.
有关更高级的格式化,包括部分序列化以避免必须为不应序列化的类声明格式化程序,请参阅JSON Reads/Writes/Format Combinators。
It should be kept in mind that the classes to be serialized don't necessarily have to be the domain model classes. It may be helpful to declare data transfer object (DTO) classes that reflect the desired JSON structure, and instantiate them from the domain model. This way, serialization is straightforward with Json.formatand there isn't the issue of partial serialization, with the added benefit of a typesafe representation of the JSON API.
应该记住,要序列化的类不一定是域模型类。声明反映所需 JSON 结构的数据传输对象 (DTO) 类并从域模型中实例化它们可能会有所帮助。通过这种方式,序列化很简单,Json.format并且不存在部分序列化的问题,并且具有 JSON API 的类型安全表示的额外好处。
For example, this BookDTO.scalafile defines a BookDTOdata transfer object that uses only types that can be serialized to JSON without requiring further definition:
例如,此BookDTO.scala文件定义了一个BookDTO数据传输对象,该对象仅使用可序列化为 JSON 的类型而无需进一步定义:
package dtos
import models._
import play.api.libs.json.Json
case class BookDTO (title: String, authors: Seq[String])
object BookDTO {
def fromBook(b: Book) = BookDTO(b.title, b.authors.map(_.name))
implicit val bookDTOFormat = Json.format[BookDTO]
}
and this JsonExample2.scalafile shows how to use this pattern:
这个JsonExample2.scala文件展示了如何使用这个模式:
package controllers
import dtos._
import dtos.BookDTO._
import models._
import play.api.mvc._
import play.api.libs.json._
import play.api.libs.functional.syntax._
object JsonExample2 extends Controller {
def listBooks = Action {
val books = Seq(
Book("Book One", Seq(Author("Author One"))),
Book("Book Two", Seq(Author("Author One"), Author("Author Two")))
)
val booksDTO = books.map(BookDTO.fromBook(_))
Ok(Json.toJson(booksDTO))
}
}

