2017-09-13 14 views
1

私は次のシナリオを持っている:Jsonからplay-jsonを使って余分な(キー、値)をスカラーで抽出する方法は?

ここ
case class Person(id: Int, name: String) 
val json = Json.obj("id" -> 1, "name" -> "John", "address"-> "Paris", "contact" -> "1234") 

、私は{ "アドレス"、すなわち、余分な(キー、値)からJSONを抽出したい - > "パリ"、 "接触" - > "1234"} に属していない

私はこれまでのところ、以下のアプローチを開発しました:これは、しかし、ここで働く

case class Person(id: Int, name: String) 
    val personReads = Json.reads[Person] 
    val personWrites = Json.writes[Person] 
    val json = Json.obj("id" -> 1, "name" -> "John", "address"-> "Paris", "contact" -> "1234") 

    val person: Person = personReads.reads(json).get 

    // This person json does not have extra fields 
    val personJson: JsObject = personWrites.writes(person).asInstanceOf[JsObject] 

    val extraKeys = json.keys.diff(personJson.keys) 

    val extraJson = extraKeys.foldLeft(Json.obj()){(result,key) => 
          result.+(key -> json.\(key).get)} 

    // {"address":"Paris","contact":"1234"} 

私はケースクラスの変換にJSONの多くを行う必要があります。このシナリオで(キー、値)を抽出する最良の方法は何ですか?

+0

はい右利用可能であり、私は私のユースケースのためにそれらの余分JSONを保持したいです。また、ケースクラスに余分なフィールドを追加する必要もありません。 – oblivion

答えて

3

大文字と小文字を区別しないようにするには、Readsを使用してください。大文字と小文字を区別せずに、大文字と小文字を区別して解析したいオブジェクトからそれらを削除します。

など。リフレクションを使用して、これは一度だけケースクラスのインスタンスを作成し、全くWritesを必要としません:

import play.api.libs.json._ 
import scala.reflect.runtime.universe._ 

def withExtra[A: Reads: TypeTag]: Reads[(A, JsObject)] = { 
    val ccFieldNames = typeOf[A].members.collect { 
    case m: MethodSymbol if m.isCaseAccessor => m.name.toString 
    }.toVector 

    for { 
    jsObj <- implicitly[Reads[JsObject]] 
    a <- implicitly[Reads[A]] 
    filteredObj = ccFieldNames.foldLeft(jsObj)(_ - _) 
    } yield (a, filteredObj) 
} 
をそして、例えば、それを使用します以下のようなので:

case class Person(id: Int, name: String) 
case class Location(id: Int, address: String) 

val json = Json.obj("id" -> 1, "name" -> "John", "address"-> "Paris", "contact" -> "1234") 

implicit val pReads = Json.reads[Person] 
implicit val lReads = Json.reads[Location] 

assert { withExtra[Person].reads(json).get == (
    Person(1, "John"), 
    Json.obj("address"-> "Paris", "contact" -> "1234") 
) } 

assert { withExtra[Location].reads(json).get == (
    Location(1, "Paris"), 
    Json.obj("name" -> "John", "contact" -> "1234") 
) } 

のRunnableコードがthere

+0

それは素晴らしいです!まさに私が探していたもの。ありがとう – oblivion

関連する問題