【问题标题】:Scala Play Json Format for Map[Locale, String]Scala Play Json 格式的地图[语言环境,字符串]
【发布时间】:2016-03-09 05:28:09
【问题描述】:

我有类型的对象

Map[java.util.Locale, String] 

我怎样才能为此进行 Json 写入/读取?我看过coupleotherquestions,但自己想不出解决方案。我得到了(但尚未测试)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)
}

我怎样才能在

中使用它
implicit val myMapReads: Reads[Map[Locale, String]] = ???
implicit val myMapWrites: Writes[Map[Locale, String]] = ???

?

【问题讨论】:

    标签: json scala playframework play-json


    【解决方案1】:

    这应该可行:

    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
      }
    }
    

    基本上 play 已经知道如何将 Locale 转换为 json,因为您提供了 Writes,因此只需调用 toJson 即可。

    对于Reads,它有点复杂,您必须进行映射,.value 返回一个Map[String, JsValue],其中第一个代表Locale 对象,第二个是一个简单的字符串,因此调用as[String] 将已经给你你想要的了。

    请注意,我已将所有内容包装在 JsSuccess 中,但您可能会认为您获得的 json 无法转换为 JsObject,应用 try/catch,并决定您要返回成功还是失败。

    【讨论】:

    • 谢谢 - 你让我走上正轨!出于某种原因,myMapWrites 中的 override def writes(o: Map[Locale, String]): JsValue = Json.toJson(o) 进入了无限递归循环,最终会触发 StackOverflowException (!!),但很容易修复。
    【解决方案2】:

    如果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) }
        }
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-05
      • 1970-01-01
      • 1970-01-01
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-21
      相关资源
      最近更新 更多