繁体   English   中英

Play JSON的不可变地图(反序列化)

[英]immutable Map (de)serialization to/from Play JSON

我有以下(简化)的结构:

case class MyKey(key: String)
case class MyValue(value: String)

假设两个案例类都有Play JSON格式化程序。

例如,我有:

val myNewMessage = collection.immutable.Map(MyKey("key1") -> MyValue("value1"), MyKey("key2") -> MyValue("value2"))

经过以下转换

play.api.libs.json.Json.toJson(myNewMessage)

我期望的是这样的:

{ "key1": "value1", "key2": "value2" }

我尝试编写格式化程序,但是以某种方式我无法成功:

implicit lazy val mapMyKeyMyValueFormat: Format[collection.immutable.Map[MyKey, MyValue]] = new Format[collection.immutable.Map[MyKey, MyValue]] {
  override def writes(obj: collection.immutable.Map[MyKey, MyValue]): JsValue = Json.toJson(obj.map {
    case (key, value) ⇒ Json.toJson(key) -> Json.toJson(value)
  })

  override def reads(json: JsValue): JsResult[collection.immutable.Map[MyKey, MyValue]] = ???
}

我不知道如何编写适当的reads功能。 有没有更简单的方法? 我对自己的writes函数也不满意。

谢谢!

writes方法不起作用的原因是因为您要将Map[MyKey, MyValue]转换为Map[JsValue, JsValue] ,但无法将其序列化为JSON。 JSON键必须是字符串,因此您需要某种方式将MyKey转换为某些唯一的String值。 否则,您将尝试序列化以下内容:

{"key": "keyName"} : {"value": "myValue"}

无效的JSON。

如果MyKey像您的问题中所述的那么简单,则可以使用:

def writes(obj: Map[MyKey, MyValue]): JsValue = Json.toJson(obj.map {
    case (key, value) => key.key -> Json.toJson(value)
})                     //   ^ must be a String

如果有适当的Writes[MyValue] ,Play将知道如何序列化Map[String, MyValue] Writes[MyValue]

但是我不确定那不是您想要的。 因为它产生了这个:

scala> Json.toJson(myNewMessage)
res0: play.api.libs.json.JsValue = {"key1":{"value":"value1"},"key2":{"value":"value2"}}

如果这是您想要的输出:

{ "key1": "value1", "key2": "value2" }

然后您的Writes应该看起来像这样:

def writes(obj: Map[MyKey, MyValue]): JsValue = {
    obj.foldLeft(JsObject(Nil)) { case (js, (key, value)) =>
         js ++ Json.obj(key.key -> value.value)
    }
}

产生此:

scala> writes(myNewMessage)
res5: play.api.libs.json.JsValue = {"key1":"value1","key2":"value2"}

只要MyKeyMyValue的结构相同, Reads就很容易,否则我不知道您希望它做什么。 这很大程度上取决于您想要的实际结构。 Reads[Map[String, String]] ,我建议利用现有的Reads[Map[String, String]]并将其转换为所需的类型。

def reads(js: JsValue): JsResult[Map[MyKey, MyValue]] = {
    js.validate[Map[String, String]].map { case kvMap =>
        kvMap.map { case (key, value) => MyKey(key) -> MyValue(value) }
    }
}

如果不知道数据的实际结构,很难看到其他内容。 通常,我不必对Map进行序列化和反序列化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM