2017-09-13 96 views
1

我有一個以下情形:如何使用scala中的play-json從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沒有任何特別之處,則可以使用反射或無形來提取案例類名稱,然後從要分析的對象中刪除這些名稱。

E.g.使用反射,這將創建一個案例類實例一次,不需要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") 
) } 

運行的代碼,請there

+0

這是優秀的!正是我在找什麼。謝謝 – oblivion

相關問題