Ответ 1
Определите форматы, соответствующие их порядку зависимости, для каждого класса в графе, который должен быть сериализован.
Форматирование 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.
Следует иметь в виду, что классы, которые должны быть сериализованы, необязательно должны быть классами модели домена. Может быть полезно объявить классы объектов передачи данных (DTO), которые отражают желаемую структуру JSON, и создать их экземпляр из модели домена. Таким образом, сериализация является простой с 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))
}
}