如何在平面级别将JsValue合并到JsObject [英] How to merge a JsValue to JsObject in flat level
问题描述
我从案例类中创建了两个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屋!