[英]How to extract extra (key,value) from Json using play-json in scala?
I have a following scenario: 我有以下情况:
case class Person(id: Int, name: String)
val json = Json.obj("id" -> 1, "name" -> "John", "address"-> "Paris", "contact" -> "1234")
Here, I want to extract extra (key,value) from json ie {"address"-> "Paris", "contact" -> "1234"} that do not belong to Person . 在这里,我想从json中提取额外的(键,值) ,即不属于Person的 {“address” - >“Paris”,“contact” - >“1234”} 。
I have developed following approach so far: 到目前为止我已经开发了以下方法:
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"}
This works but here I have to do a lot of json to case class conversions. 这有效但在这里我必须做很多json到case类的转换。 What would be the best way to extract extra (key,value) in this scenario ?
在这种情况下,提取额外(键,值)的最佳方法是什么?
If you want to make it general for any case class and not doing anything fancy with custom Reads
, you can use reflection or shapeless to extract case class names and then remove those from an object you're trying to parse. 如果你想让它适用于任何案例类而不想使用自定义
Reads
做任何事情,你可以使用反射或无形来提取案例类名称,然后从你想要解析的对象中删除它们。
Eg using reflection, this only creates a case class instance once and does not require Writes
at all: 例如,使用反射,这只创建一个case类实例一次,根本不需要
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)
}
And use it eg like so: 并使用它,例如:
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")
) }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.