如何在平面级别将JsValue合并到JsObject [英] How to merge a JsValue to JsObject in flat level

查看:181
本文介绍了如何在平面级别将JsValue合并到JsObject的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从案例类中创建了两个JsValue,即Book和Book detail

I have two JsValue created from case class, i.e. Book and Book detail

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
}

如何在游戏框架2.10中将它们合并到单个Json?即

How can I merge them to a single Json in play-framework 2.10? i.e.

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

我正在尝试进行转换,但是未能遍历第二个JsValue:

I was trying the transformation and failed to iterate through the second JsValue:

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

bookJson.validate(mapDetail).get

它将下降一级,我真的不想要.

It would become one level down, which I don't really want.

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

请让我知道此Json转换是否可以提供任何技巧.非常感谢!

Please let me know if any trick could provide on this Json transform. Many Thanks!

推荐答案

Play现在具有JSON的许多新功能.这可以很好地展示Format[A]特性(请参阅 Scala Json Inception ).如我将显示的那样,隐式地或需要隐式Format[A]/Reads[A]/Writes[A]的方法的显式.

Play has a lot of new features for JSON right now. This would be a nice showcase for the Format[A] trait (see Scala Json Inception) which you could include implicitly as I will show, or explicitly to the methods that require an implicit Format[A]/Reads[A]/Writes[A].

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

Create a case class to represent your JSON objects,

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

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

Create companion objects that contain the implicit Format[A] so that Format/Reads/Writes will automatically be in scope when you need them.

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

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

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

Now you could do something like this,

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])

您将拥有一个像这样的对象

And you will have an object like this,

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

我已经在REPL中尝试过此方法,但是它不起作用,但是在Play应用程序中它可以正常运行.同样在生产场景中,我们可能会使用asOpt[T]代替as[T].

I've tried this in the REPL but it does not work, in a Play application it does just fine though. Also in a production scenario we would likely use asOpt[T] in place of as[T].

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

Here is an example of why asOpt[T] may be better suited, suppose instead of a valid JSON object for book you get,

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

您最终会得到

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

但是,假设您改为将方法更改为使用asOpt[T]

But suppose instead you change your method to use asOpt[T],

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

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

Now you will end up with at least a partial JSON object,

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

因此,根据您要如何处理格式不正确的JSON,可以选择其中一个选项.

So depending on how you would like to handle improperly formatted JSON you could choose either option.

这篇关于如何在平面级别将JsValue合并到JsObject的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆