Play Framework: нет неявного формата для карты - PullRequest
2 голосов
/ 05 июня 2019

При использовании 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].Попробуйте реализовать неявную запись или форматирование для этого типа.

Если не пропущено что-то очевидное, существует неявный формат для этого типа непосредственно выше.

Если я попробую что-тоболее просто, как:

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

Работает нормально.Чего мне не хватает при использовании Map с более сложным типом, например SomeCaseClass?

Ответы [ 2 ]

4 голосов
/ 05 июня 2019

Я думаю, что проблема здесь исходит от JSON. Карты преобразуются в объекты JSON, которые состоят из пар ключ / значение. Ключи в этих объектах must являются строками.

Таким образом, Map[String, T] может быть преобразован в объект json, но не произвольный Map[U, T].

1 голос
/ 05 июня 2019

@ Джек Борн прав.Карта обрабатывается как JsObject в play json, и поэтому ключ должен быть сериализуем для строкового значения.

Вот пример кода, который можно использовать для определения формата карты

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