简体   繁体   English

在Play中将Seq映射到JSON

[英]Mapping Seq to JSON in Play

I'm trying to map a Scala case class to JSON using Play 2.x. 我正在尝试使用Play 2.x将Scala案例类映射到JSON。 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. 这适用于案例类的简单版本,但是当涉及到Seq或对象列表时则不适用:然后我得到“无隐式格式”和“找不到未应用函数”错误。

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.format macro 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. 没有Seq它可以很好地工作,但是使用Seq,它会失败。 I tried adding implicit val authorsFormat = Json.format[Seq[Author]] to the implicit converters, but that has no effect. 我尝试将implicit val authorsFormat = Json.format[Seq[Author]]到隐式转换器,但这没有任何效果。

Define the formatters respecting their dependency order, for each class in the graph that needs to be serialized. 为需要序列化的图中的每个类定义遵循其依赖顺序的格式化程序。

Formatting Book requires formatting Author , so define the Author formatter before the Book formatter. 格式化Book需要格式化Author ,因此在Book格式化程序之前定义Author格式化程序。

For example, with this Models.scala file: 例如,使用此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.scala file: 和这个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 listBooks will 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读取/写入/格式化组合器

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. 声明反映所需JSON结构的数据传输对象(DTO)类并从域模型实例化它们可能会有所帮助。 This way, serialization is straightforward with Json.format and there isn't the issue of partial serialization, with the added benefit of a typesafe representation of the JSON API. 这样,使用Json.format可以直接进行序列化,并且不存在部分序列化的问题,并且具有JSON API的类型安全表示的额外好处。

For example, this BookDTO.scala file defines a BookDTO data 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.scala file 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))
  }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM