I have two JsValue created from case class, i.e. Book and Book detail
val bookJson = Json.tojson(Book)
val bookDetailJson = Json.tojson(BookDetail)
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]
.
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)
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
}
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]
.
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")
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]
,
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,
{
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.