播放框架:地图没有隐式格式

时间:2019-06-05 08:24:17

标签: scala playframework playframework-2.5 play-json

使用Play 2.5我似乎无法序列化Map[SomeCaseClass, String]

case class SomeCaseClass(value: String)

implicit val formatSomeCaseClass = Json.format[SomeCaseClass]

Json.toJson(Map[SomeCaseClass, String](SomeCaseClass("") -> ""))

错误

  

找不到用于类型的Json序列化器   scala.collection.immutable.Map [SomeCaseClass,String]。尝试实施   这种类型的隐式Writes或Format。

除非我遗漏了一些明显的内容,否则在上面紧紧地存在该类型的隐式格式。

如果我尝试更简单的方法:

Json.toJson(Something(""))
Json.toJson(Map[String, String]("" -> ""))

工作正常。在使用Map和更复杂的类型(例如SomeCaseClass

2 个答案:

答案 0 :(得分:4)

我认为这里的问题来自json。映射将转换为由键/值对组成的JSON对象。这些对象must中的键是字符串。

因此,Map[String, T]可以转换为json对象,但不能转换为任意Map[U, T]

答案 1 :(得分:1)

@Jack Bourne是正确的。映射在play json中被视为JsObject,因此该键必须可序列化为字符串值。

这是示例代码,可用于定义地图格式

import play.api.libs.json._

case class SomeCaseClass(value: String)

implicit val formatSomeCaseClass = Json.format[SomeCaseClass]

Json.toJson(Map[SomeCaseClass, String](SomeCaseClass("") -> ""))

implicit val someCaseClassToStringFormat = new Format[Map[SomeCaseClass, String]] {
override def writes(o: Map[SomeCaseClass, String]): JsValue = {
  val tuples = o.toSeq.map {
    case (key, value) => key.value -> Json.toJsFieldJsValueWrapper(value)
  }
  Json.obj(tuples: _*)
}

override def reads(json: JsValue): JsResult[Map[SomeCaseClass, String]] = {
  val resultMap: Map[SomeCaseClass, String] = json.as[JsObject].value.toSeq.map {
    case (key, value) => Json.fromJson[SomeCaseClass](value) match {
      case JsSuccess(someCaseClass, _) => someCaseClass -> key
      case JsError(errors) => throw new Exception(s"Unable to parse json :: $value as SomeCaseClass because of ${JsError.apply(errors)}")
    }
  }(collection.breakOut)
  JsSuccess(resultMap)
 }
}