scala 如何在平面级别将 JsValue 合并到 JsObject
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17596809/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to merge a JsValue to JsObject in flat level
提问by Joyfulvillage
I have two JsValue created from case class, i.e. Book and Book detail
我有两个从案例类创建的 JsValue,即 Book 和 Book detail
val bookJson = Json.tojson(Book)
val bookDetailJson = Json.tojson(BookDetail)
and the format would be:
格式为:
//Book
{
id: 1,
name: "A Brief History of Time"
}
//BookDetail
{
bookId: 1,
author: "Steven Hawking",
publicationDate: 1988,
pages: 256
}
How can I merge them to a single Json in play-framework 2.10? i.e.
如何在 play-framework 2.10 中将它们合并为单个 Json?IE
//Book with detail
{
id: 1,
name: "A Brief History of Time",
bookId: 1,
author: "Steven Hawking",
publicationDate: 1988,
pages: 256
}
I was trying the transformation and failed to iterate through the second JsValue:
我正在尝试转换,但未能遍历第二个 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
}
}
Please let me know if any trick could provide on this Json transform. Many Thanks!
请让我知道是否可以在此 Json 转换上提供任何技巧。非常感谢!
回答by tysonjh
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].
Play 现在为 JSON 提供了许多新功能。这将是Format[A]trait(参见Scala Json Inception)的一个很好的展示,你可以像我将展示的那样隐式包含它,或者显式包含到需要隐式Format[A]/Reads[A]/Writes[A].
Create a case class to represent your JSON objects,
创建一个案例类来表示您的 JSON 对象,
case class Book(id: Int, name: String)
case class BookDetail(id: Int, author: String, publicationDate: Int, pages: Int)
Create companion objects that contain the implicit Format[A]so that Format/Reads/Writeswill automatically be in scope when you need them.
创建包含隐式的伴生对象,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]
}
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
}
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].
我已经在 REPL 中尝试过这个,但它不起作用,但在 Play 应用程序中它做得很好。此外,在生产场景中,我们可能会使用asOpt[T]代替as[T]。
Here is an example of why asOpt[T]may be better suited, suppose instead of a valid JSON object for book you get,
这是一个为什么asOpt[T]可能更适合的示例,假设您获得的书不是有效的 JSON 对象,
val bookJson = Json.toJson("not a book")
You will end up with a
你会得到一个
[JsResultException: JsResultException(errors:List((,List(ValidationError(validate.error.expected.jsobject,WrappedArray())))))]
But suppose instead you change your method to use asOpt[T],
但是假设你改变了你的方法来使用asOpt[T],
bookJson.asOpt[JsObject].getOrElse(Json.obj()).deepMerge(bookDetailJson.asOpt[JsObject].getOrElse(Json.obj()))
Now you will end up with at least a partial JSON object,
现在你至少会得到一个部分的 JSON 对象,
{
id: 1,
author: "Steven Hawking",
publicationDate: 1988,
pages: 256
}
So depending on how you would like to handle improperly formatted JSON you could choose either option.
因此,根据您希望如何处理格式不正确的 JSON,您可以选择任一选项。
回答by albgorski
JsObject is subtype of JsValue.
JsObject 是 JsValue 的子类型。
JsValue can be simple converted to the JsObject using asor asOptmethods from JsValue. Example:
可以使用 JsValue 中的as或asOpt方法将 JsValue 简单转换为JsObject。例子:
val someJsValue = ....
val asObject:JsObject = someJsValue.as[JsObject]
val asObjectMaybe:Option[JsObject] = v.asOpt[JsObject]
In the case of JsArrayyou can not use above code. If you use play and parse JSON with array, then Json.toJson(...)produces JsValue which is JsArray actually. You need to convert JsArray as following:
在JsArray的情况下,您不能使用上面的代码。如果你使用 play 并用数组解析 JSON,那么Json.toJson(...)会产生 JsValue,它实际上是 JsArray。您需要按如下方式转换 JsArray:
val someJsValueButArray = ....
val asJsArray:JsArray = Json.toJson(someJsValueButArray).as[JsArray]
val asSeqOfJsObjects:Seq[JsObject] = asJsArray.value.map(_.as[JsObject])

