如何在scala中使用play Json从Json中提取额外的(键、值)?

如何在scala中使用play Json从Json中提取额外的(键、值)?,scala,play-json,Scala,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(

我有以下一个场景:

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到case类的转换。在这种情况下,提取额外的(键、值)的最佳方法是什么?

如果您想使其适用于任何case类,并且不需要对自定义
读取进行任何处理,您可以使用反射或无形状提取case类名,然后从尝试解析的对象中删除这些名称

例如,使用反射,这只创建一个案例类实例一次,根本不需要
写入

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)
}

可运行的代码是可用的

Yes right,我想为我的用例保留这些额外的json。我也不想在case类中添加额外的字段。
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")
) }