json - 如何在平面级别将 JsValue 合并到 JsObject

标签 json scala playframework-2.0

我有两个从案例类创建的 JsValue,即书籍和书籍详细信息

val bookJson = Json.tojson(Book)
val bookDetailJson = Json.tojson(BookDetail)

格式为:

//Book
{
  id: 1,
  name: "A Brief History of Time"
}

//BookDetail
{
  bookId: 1,
  author: "Steven Hawking",
  publicationDate: 1988,
  pages: 256
}

如何在 play-framework 2.10 中将它们合并到单个 Json 中?即

//Book with detail
{
  id: 1,
  name: "A Brief History of Time",
  bookId: 1,
  author: "Steven Hawking",
  publicationDate: 1988,
  pages: 256
}

我正在尝试转换,但未能迭代第二个 JsValue:

val mapDetail = (__).json.update(
                  __.read[JsObject].map { o =>
                  o.deepMerge( JsObject(Seq(("detail", bookDetailJson))) )
                })

bookJson.validate(mapDetail).get

它会降低一级,这是我真正不想要的。

//Book with detail
{
  id: 1,
  name: "A Brief History of Time",
  detail: {
            bookId: 1,
            author: "Steven Hawking",
            publicationDate: 1988,
            pages: 256
          }
}

请告诉我是否可以在此 Json 转换上提供任何技巧。非常感谢!

最佳答案

Play 现在有很多针对 JSON 的新功能。这将是 Format[A] 特征(参见 Scala Json Inception )的一个很好的展示,您可以像我将要展示的那样隐式包含它,或者显式包含需要隐式 Format[ 的方法A]/读取[A]/写入[A]

创建一个案例类来表示您的 JSON 对象,

case class Book(id: Int, name: String)
case class BookDetail(id: Int, author: String, publicationDate: Int, pages: Int)

创建包含隐式Format[A]的伴随对象,以便在需要时Format/Reads/Writes自动位于范围内。

object Book { 
  implicit val fmt: Format[Book] = Json.format[Book] 
}

object BookDetail { 
  implicit val fmt: Format[BookDetail] = Json.format[BookDetail] 
}

现在你可以做这样的事情,

val bookJson = Json.toJson(Book(1, "A Brief History Of Time"))
val bookDetailJson = Json.toJson(BookDetail(1, "Steven Hawking", 1988, 256))
bookJson.as[JsObject].deepMerge(bookDetailJson.as[JsObject])

你将拥有一个像这样的对象,

{
  id: 1,
  name: "A Brief History Of Time",
  author: "Steven Hawking",
  publicationDate: 1988,
  pages: 256
}

我已经在 REPL 中尝试过了,但它不起作用,但在 Play 应用程序中它却表现得很好。同样在生产场景中,我们可能会使用 asOpt[T] 代替 as[T]

这里是为什么 asOpt[T] 可能更适合的示例,假设您获得的书籍不是有效的 JSON 对象,

val bookJson = Json.toJson("not a book")

你最终会得到一个

[JsResultException: JsResultException(errors:List((,List(ValidationError(validate.error.expected.jsobject,WrappedArray())))))]

但是假设您更改方法以使用 asOpt[T]

bookJson.asOpt[JsObject].getOrElse(Json.obj()).deepMerge(bookDetailJson.asOpt[JsObject].getOrElse(Json.obj()))

现在您将至少得到一个部分 JSON 对象,

{
  id: 1,
  author: "Steven Hawking",
  publicationDate: 1988,
  pages: 256
}

因此,根据您希望如何处理格式不正确的 JSON,您可以选择任一选项。

关于json - 如何在平面级别将 JsValue 合并到 JsObject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17596809/

相关文章:

json - Bash 解析 JSON 对象 jsawk

Java - 以分钟为单位计算差异

php - REST API - 为什么使用 PUT DELETE POST GET?

scala - 将数据库架构与现有的光滑表进行比较

java - Play! 框架和 Akka 讲述

c# - Automapper:将 JSON 转换为对象列表

scala - 为什么 scala 允许使用 Option[Strings](或任何其他类型)连接字符串?

scala - 反射可以提取特征中使用的初始值吗?

javascript - 在 Play Framework 2 中使用 javascript 路由

amazon-ec2 - 在Amazon EC2微型实例中运行Play框架应用