ケースクラスから作成された2つのJsValue、つまり本と本の詳細があります
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
}
Play-Framework 2.10でそれらを単一のJsonにマージするにはどうすればよいですか?つまり.
//Book with detail
{
id: 1,
name: "A Brief History of Time",
bookId: 1,
author: "Steven Hawking",
publicationDate: 1988,
pages: 256
}
変換を試みていましたが、2番目のJsValueを反復処理できませんでした。
val mapDetail = (__).json.update(
__.read[JsObject].map { o =>
o.deepMerge( JsObject(Seq(("detail", bookDetailJson))) )
})
bookJson.validate(mapDetail).get
それは1レベル下になるでしょう、それは私が本当に望んでいないことです。
//Book with detail
{
id: 1,
name: "A Brief History of Time",
detail: {
bookId: 1,
author: "Steven Hawking",
publicationDate: 1988,
pages: 256
}
}
このJson変換で何かトリックが提供できるかどうか教えてください。どうもありがとう!
Playには現在JSONの多くの新機能があります。これは、Format[A]
トレイト( Scala Json Inception を参照)の優れたショーケースであり、これから説明するように暗黙的に含めるか、暗黙的なFormat[A]/Reads[A]/Writes[A]
を必要とするメソッドに明示的に含めることができます。
JSONオブジェクトを表すケースクラスを作成し、
case class Book(id: Int, name: String)
case class BookDetail(id: Int, author: String, publicationDate: Int, pages: Int)
暗黙の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]
}
今、あなたはこのようなことをすることができます、
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])
そして、あなたはこのようなオブジェクトを持つでしょう、
{
id: 1,
name: "A Brief History Of Time",
author: "Steven Hawking",
publicationDate: 1988,
pages: 256
}
私はこれをREPLで試しましたが、機能しません。Playアプリケーションでは問題なく動作します。また、本番シナリオでは、asOpt[T]
の代わりにas[T]
を使用する可能性があります。
これは、asOpt[T]
がより適している理由の例です。取得した本の有効なJSONオブジェクトの代わりに、
val bookJson = Json.toJson("not a book")
あなたは最終的に
[JsResultException: JsResultException(errors:List((,List(ValidationError(validate.error.expected.jsobject,WrappedArray())))))]
ただし、代わりにasOpt[T]
を使用するようにメソッドを変更するとします。
bookJson.asOpt[JsObject].getOrElse(Json.obj()).deepMerge(bookDetailJson.asOpt[JsObject].getOrElse(Json.obj()))
これで、少なくとも部分的なJSONオブジェクトができあがります。
{
id: 1,
author: "Steven Hawking",
publicationDate: 1988,
pages: 256
}
したがって、不適切にフォーマットされたJSONをどのように処理するかに応じて、いずれかのオプションを選択できます。
JsObjectはJsValueのサブタイプです。
JsValueは、asまたはasOptメソッドを使用してJsObjectに簡単に変換できます。 JsValue。例:
val someJsValue = ....
val asObject:JsObject = someJsValue.as[JsObject]
val asObjectMaybe:Option[JsObject] = v.asOpt[JsObject]
JsArrayの場合では、上記のコードは使用できません。 playを使用して配列でJSONを解析すると、Json.toJson(...)は実際にはJsArrayであるJsValueを生成します。 JsArrayを次のように変換する必要があります。
val someJsValueButArray = ....
val asJsArray:JsArray = Json.toJson(someJsValueButArray).as[JsArray]
val asSeqOfJsObjects:Seq[JsObject] = asJsArray.value.map(_.as[JsObject])