简体   繁体   English

Map的Scala Play Json格式[语言环境,字符串]

[英]Scala Play Json Format for Map[Locale, String]

I have objects of type 我有类型的对象

Map[java.util.Locale, String] 

How can I make Json Writes / Reads for this? 我该如何让Json进行读写操作? I have looked at a couple other questions , but couldn't come up with a solution myself. 我看了其他 几个 问题 ,但本人无法解决。 I got (but not tested yet) something for Locale 我有(但尚未测试)适用于Locale的内容

implicit val localeReads: Reads[Locale] = new Reads[Locale] {
  def reads(json: JsValue): JsResult[Locale] =
    json match {
      case JsString(langString) => JsSuccess(new Locale(langString))
      case _ => JsError("Locale Language String Expected")
    }
}

implicit val localeWrites: Writes[Locale] = new Writes[Locale] {
  def writes(locale: Locale) = JsString(locale.toString)
}

How can I then use this in 然后我该如何使用

implicit val myMapReads: Reads[Map[Locale, String]] = ???
implicit val myMapWrites: Writes[Map[Locale, String]] = ???

?

This should work: 这应该工作:

implicit val localeReads: Reads[Locale] = new Reads[Locale] {
  def reads(json: JsValue): JsResult[Locale] =
    json match {
      case JsString(langString) => JsSuccess(new Locale(langString))
      case _ => JsError("Locale Language String Expected")
    }
}

implicit val localeWrites: Writes[Locale] = new Writes[Locale] {
  def writes(locale: Locale) = JsString(locale.toString)
}

implicit val myMapWrites: Writes[Map[Locale, String]] = new Writes[Map[Locale, String]] {
  override def writes(o: Map[Locale, String]): JsValue = Json.toJson(o)
}

implicit val myMapRead: Reads[Map[Locale, String]] = new Reads[Map[Locale, String]] {
  override def reads(json: JsValue): JsResult[Map[Locale, String]] = JsSuccess {
    json.as[JsObject].value.map {
      case (k, v) => (new Locale(k), v.as[String])
    }.toMap
  }
}

Basically play already knows how to convert a Locale to json because of the Writes you provided so simply calling toJson will work. 由于您提供了Writes ,因此play基本上已经知道如何将Locale转换为json,因此只需调用toJson即可。

For the Reads it's a bit more complex and you have to do a mapping, .value returns a Map[String, JsValue] where the first represents the Locale object and the second a simple string so calling as[String] will already give you what you want. 对于Reads来说,它有点复杂,您必须进行映射, .value返回Map[String, JsValue] ,其中第一个表示Locale对象,第二个表示简单字符串,因此调用as[String]已经可以为您提供你要。

Note that I've wrapped everything in a JsSuccess but you may assume that the json you got cannot be converted to JsObject , apply a try/catch, and decide wether you want to return success or failure. 请注意,我已经将所有内容包装在JsSuccess但是您可能会假设无法将获得的json转换为JsObject ,无法进行try / catch并决定是否要返回成功或失败。

Here's a function that will create a Format[K,V] for you if K serialises to a JsString : 如果K序列JsString ,则此函数将为您创建Format[K,V]

/** Play Json only supports Map[String,V]. This function creates a format for Map[K,V]. The type K should produce a JsString.
 * Otherwise the serialisation will fail. Which should be good enough since in valid json keys can only be strings. 
*/
def mapFormat[K, V](implicit fk: Format[K], fv: Format[V]): Format[Map[K, V]] = 
  new OFormat[Map[K, V]] {
    override def writes(o: Map[K, V]): JsObject = {
      val stringMap = o.map { case (k, v) => (Json.toJson[K](k).as[JsString].value, v) }
      Json.toJson(stringMap).as[JsObject]
    }

    override def reads(json: JsValue): JsResult[Map[K, V]] = {
      for {
        stringMap <- Json.fromJson[Map[String, V]](json)
        _         <- Json.fromJson[Set[K]](Json.toJson(stringMap.keySet))
      } yield stringMap.map { case (k, v) => (Json.fromJson[K](JsString(k)).get, v) }
    }
  }

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

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