我尝试使用Play 2.x将Scala案例类映射到JSON。这适用于案例类的简单版本,但不适用于涉及Seq或对象列表的情况:那么我没有隐式格式'并且没有找到未应用的功能'错误。
我使用的代码如下:
case class Book(title: String, authors: Seq[Author])
case class Author(name: String)
我已使用Json.format
宏为此生成读取和写入:
implicit val bookFormat = Json.format[Book]
implicit val authorFormat = Json.format[Author]
但是现在当我编写代码时,我收到以下错误:
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]
^
没有Seq它可以很好地工作,但是使用Seq,它会失败。我尝试将implicit val authorsFormat = Json.format[Seq[Author]]
添加到隐式转换器,但这没有效果。
答案 0 :(得分:10)
为图中需要序列化的每个类定义遵循其依赖顺序的格式化程序。
格式化Book
需要格式化Author
,因此请在Author
格式化程序之前定义Book
格式化程序。
例如,使用此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]
}
和此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)
}
}
对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"}]}]
对于更高级的格式设置,包括部分序列化以避免必须为不应序列化的类声明格式化程序,请参阅JSON Reads/Writes/Format Combinators。
应该记住,要序列化的类不一定必须是域模型类。声明反映所需JSON结构的数据传输对象(DTO)类并从域模型实例化它们可能会有所帮助。这样,使用Json.format
可以直接进行序列化,并且不存在部分序列化的问题,并且具有JSON API的类型安全表示的额外好处。
例如,此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]
}
并且此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))
}
}