简体   繁体   English

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

[英]How to merge a JsValue to JsObject in flat level

I have two JsValue created from case class, ie Book and Book detail 我有两个从case类创建的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? 如何将它们合并到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. 请让我知道这个Json转换是否可以提供任何技巧。 Many Thanks! 非常感谢!

Play has a lot of new features for JSON right now. Play现在具有JSON的许多新功能。 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] . 这将很好地展示Format[A]特性(请参见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/Writes will 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. 我已经在REPL中尝试过此方法,但是它不起作用,但是在Play应用程序中就可以了。 Also in a production scenario we would likely use asOpt[T] in place of as[T] . 同样在生产场景中,我们可能会使用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,可以选择其中一个选项。

JsObject is subtype of JsValue. JsObject是JsValue的子类型。

JsValue can be simple converted to the JsObject using as or asOpt methods from JsValue. 可以使用JsValue中的asasOpt方法将JsValue简单转换为JsObject。 Example: 例:

val someJsValue = ....
val asObject:JsObject = someJsValue.as[JsObject]
val asObjectMaybe:Option[JsObject] = v.asOpt[JsObject]

In the case of JsArray you can not use above code. 对于JsArray,您不能使用上面的代码。 If you use play and parse JSON with array, then Json.toJson(...) produces JsValue which is JsArray actually. 如果使用play并使用数组解析JSON,则Json.toJson(...)会生成JsValue,它实际上是JsArray。 You need to convert JsArray as following: 您需要按以下方式转换JsArray:

val someJsValueButArray = ....
val asJsArray:JsArray = Json.toJson(someJsValueButArray).as[JsArray]
val asSeqOfJsObjects:Seq[JsObject] = asJsArray.value.map(_.as[JsObject])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM