2016-08-23 3 views
0

せずに、未知のフィールドを持つJSONをデシリアライズ私は、次のようなJSONを持って考えてみます。プレイJSON:それらを失うこと

{ 
    "a": "aa", 
    "b": "bb", 
    "c": "cc", 
    "d": "dd", // unknown in advance 
    "e": { //unknown in advance 
    "aa": "aa" 
    } 
} 

私はJSONは、B、Cが含まれていることを確実に知っているが、私はありませんしましたこのjsonに含まれる可能性のある他のフィールド

このJSONをa、b、cを含む大文字小文字のクラスにシリアル化したいのですが、他のフィールドを失うことはありません(マップをクラスに保存して、受け取ったものと同じjsonにデシリアライズされます) 。

アイデア?

答えて

1

1つのオプションは、あなたがそれらを必要とする場合は、後から値を抽出することができ、そこからMap[String,JsValue]で「不明」のフィールドを、キャプチャすることです。

// And a writes... 
implicit val writes: Writes[MyClass] = (
    (__ \ "a").write[String] and 
    (__ \ "b").write[String] and 
    (__ \ "c").write[String] and 
    __.write[Map[String, JsValue]] 
)(unlift(MyClass.unapply _)) 

// Or combine the two... 
implicit val format: Format[MyClass] = (
    (__ \ "a").format[String] and 
    (__ \ "b").format[String] and 
    (__ \ "c").format[String] and 
    __.format[Map[String, JsValue]](Reads 
    .map[JsValue].map(_.filterKeys(k => !Seq("a", "b", "c").contains(k)))) 
)(MyClass.apply, unlift(MyClass.unapply)) 

注:

case class MyClass(a: String, b: String, c: String, extra: Map[String, JsValue]) 
implicit val reads: Reads[MyClass] = (
    (__ \ "a").read[String] and 
    (__ \ "b").read[String] and 
    (__ \ "c").read[String] and 
    __.read[Map[String, JsValue]] 
    .map(_.filterKeys(k => !Seq("a", "b", "c").contains(k))) 
)(MyClass.apply _) 

// Result: 
// MyClass(aa,bb,cc,Map(e -> {"aa":"aa"}, d -> "dd")) 

同様に、あなたはそうのようなWritesまたはFormatを行うことができますが、引数(Reads.map)としてMap[String,JsValue]明示Readsためformatを与えるので、それは少し混乱に見えます次に、既にキャプチャ値を削除するために変換します(.mapメソッド)。

+0

と書き込みはどのように見えるのですか? – arseny

1

あなたはこのためにカスタムReadsを使用することができ、何かのように:

import play.api.libs.json._ 
import play.api.libs.functional.syntax._ 

case class MyData(a: String, b: String, c:String, other: Map[String, JsValue]) 

object MyData { 
    val abcReader: Reads[(String, String, String)] = (
    (JsPath \ "a").read[String] and 
    (JsPath \ "b").read[String] and 
    (JsPath \ "c").read[String] 
).tupled 

    implicit val reader: Reads[MyData] = Reads { json => 
    abcReader.reads(json).map { 
     case (a, b, c) => 
     val other = json.as[JsObject].value -- Seq("a", "b", "c") 
     MyData(a, b, c, other.toMap) 
    } 
    } 
} 
関連する問題