如何使用Play的json序列化/反序列化动态字段名称

时间:2014-04-28 09:21:28

标签: scala playframework

我正在使用Play framework 2.2.2。 我试图像这样处理json请求

[
  {
    "id" : "123",
    "language" : "en",
    "text" : "This is an example of a text",
    "Metadata_IP" : "192.168.20.34",
    "Metadata_date" : "2001-07-04T12:08:56.235-0700"
  },
  {
    "id" : "124",
    "language" : "en",
    "text" : "Some more text here",
    "Metadata_IP" : "192.168.20.31",
    "Metadata_date" : "2001-07-04T12:09:56.235-0700",
    "Metadata_name" : "someone"
  }
]

Metadata_字段是动态字段,意味着用户可以发送他想要的内容(例如,Metadata_color等...) 处理这个问题的最佳方法是什么?

我可以使用Readers将其反序列化为case class吗?我怎样才能做到这一点?我想动态字段将是Map [String,String],但我该如何让读者解析这个?

由于

2 个答案:

答案 0 :(得分:5)

这样的事情可行:

implicit object jsObjToKeyValueSeq extends Reads[Seq[(String, String)]] {
  override def reads(json: JsValue) = json match {
    case js: JsObject => 
      JsSuccess(js.fields.collect { case (key, JsString(value)) => key -> value })
    case x => JsError(s"Unexpected json: $x")
  }
}

答案 1 :(得分:0)

我们遇到了确切的问题,并使用自定义实现解决了它。解决方案详细here

示例:

Scala类

case class Person(name: String, age: String, customFields: Map[String,String])

上述类的默认Json表示形式为:

{
 "name": "anil",
 "age": "30",
 "customFields": {
     "field1": "value1",
     "field2": "value2"
 }
}

但我们想要的是:

{
 "name": "anil",
 "age": "30",
 "field1": "value1",
 "field2": "value2"
}

这不是很直接。虽然使用play框架可以实现这一点,但我们并不想让事情太复杂化。最后,我们通过返回Map [String,String]找到了一种方法,它使用反射代表每个类(它的字段和值)并分别处理自定义字段的行为。

case class Person(name: String, age: String, customFields:CustomFields)

case class CustomFields(valueMap: Map[String,String])


def covertToMap(ref: AnyRef) =

  ref.getClass.getDeclaredFields.foldLeft(Map[String, Any]()){
    (map, field) => {
      field.setAccessible(true)
      val value = field.get(ref)
      value match {
        case c: CustomFields => {
          map ++ c.valueMap
        }
        case _ => {
          map + (field.getName -> value)
        }
      }
    }
  }

使用covertToMap()将任何案例类转换为Map,然后使用jackson json4s将此映射转换为普通Json。

val json = Serialization.write(covertToMap(person))

完整的源代码可用here