[英]Play Framework / Scala: abstract repository and Json de/serialization
[英]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"}
只要MyKey
和MyValue
的结构相同, 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.