scala-play 2.4.11, можно ли десериализовать Map с классом case в качестве ключа? - PullRequest
0 голосов
/ 25 мая 2018

Я пытаюсь разобраться с play-json, и это не очень хорошо.Вот мои классы дел

sealed case class Items(items: List[Item])

sealed case class Item(path: String, itemCounters: Map[ItemCategory, Long])

sealed case class ItemCategory(repository: Repository)

sealed case class Repository(env: String)

Здесь я пытаюсь разобрать json:

implicit lazy val repositoryFormat = Json.format[Repository]
implicit lazy val itemCategoryFormat = Json.format[ItemCategory]
implicit lazy val itemFormat = Json.format[Item]
implicit lazy val itemsFormat = Json.format[Items]

Json.parse(str).as[Items]

Я получаю исключение: Нет неявного формата для Map [ItemCategory, Long] доступно.

Почему?

1 Ответ

0 голосов
/ 25 мая 2018

Сбой, потому что play-json не понимает, как десериализовать свойство itemCounters: Map[ItemCategory, Long] в Item.

Действительно, карты JSON могут обрабатываться напрямую, если ключ - String.Но это становится немного сложнее с другими структурированными объектами в ключах, как ItemCategory в вопросе.Конечно, JSON с таким ключом не может быть { "repository": { "env": "demo" } }: 1!

Итак, нам нужно четко заявить о десериализации этого вида Map.Я предполагаю, что ключ для ItemCategory является базовым значением ItemCategory.repository.env, но это может быть любое другое свойство в зависимости от вашей эффективной модели данных.

Мы предоставляем реализацию Reads для этого видакарты:

implicit lazy val itemCategoryMapReads = new Reads[Map[ItemCategory, Long]] {
  override def reads(jsVal: JsValue): JsResult[Map[ItemCategory, Long]] = {
    JsSuccess(
      // the original string -> number map is translated into ItemCategory -> Long
      jsVal.as[Map[String, Long]].map{
        case (category, id) => (ItemCategory(Repository(category)), id)
      }
    )
  }
}

И соответствующий Format (с заглушкой для Writes, которая нам сейчас не нужна):

implicit lazy val itemCategoryMapFormat = Format(itemCategoryMapReads, (catMap: Map[ItemCategory, Long]) => ???)

Базовая версия JSON теперьотображается правильно:

val strItemCat =
  """
    | {
    |   "rep1": 1,
    |   "rep2": 2,
    |   "rep3": 3
    | }
  """.stripMargin

println(Json.parse(strItemCat).as[Map[ItemCategory, Long]])
// Map(ItemCategory(Repository(rep1)) -> 1, ItemCategory(Repository(rep2)) -> 2, ItemCategory(Repository(rep3)) -> 3)

Для других классов case-а, которые вы уже определили, простые форматы должны работать должным образом при условии, что они объявлены в порядке от наиболее к наименее конкретному (от Repository до Items).).

...