Как определить формат для Y и List [X] в Play JSON, когда X простирается от Y, а Y является чертой? - PullRequest
0 голосов
/ 17 февраля 2020

Я не могу конвертировать список в указанном c случае: когда тип расширяется от черты.

Когда я могу конвертировать:

  import play.api.libs.functional.syntax._
  import play.api.libs.json._
  sealed trait Item
  case class Id(id: Long) extends Item
  case class MyList(list: List[Id])
  object MyFormat {
    implicit lazy val idFormat = Json.format[Id]
    implicit lazy val myListFormat = Json.format[MyList]
  }

Когда я не могу конвертировать:

  sealed trait Item
  case class Id(id: Long) extends Item
  case class MyList(list: List[Id])
  object MyFormat {
    implicit lazy val itemFormat = new Format[Item] {
      override def writes(o: Item): JsValue = o match {
        case i: Id => idFormat.writes(i)
      }
      override def reads(json: JsValue): JsResult[Item] = {
        idFormat.reads(json)
      }
    }
    implicit lazy val idFormat = Json.format[Id]
    implicit lazy val myListFormat = Json.format[MyList]
  }

Ошибка: Error:(33, 49) No instance of play.api.libs.json.Format is available for scala.collection.immutable.List[Main2.Id] in the implicit scope (Hint: if declared in the same file, make sure it's declared before) implicit lazy val myListFormat = Json.format[MyList]

Почему я не могу отформатировать во 2-м случае?

Если добавить форматер для списка:

implicit lazy val idsFormat = Json.format[List[Id]]

тогда я получил Error:(33, 46) No instance of Reads is available for scala.collection.immutable.Nil in the implicit scope (Hint: if declared in the same file, make sure it's declared before) implicit lazy val idsFormat = Json.format[List[Id]]

PS: Единственное решение, которое я нашел:

  1. Определить пользовательский формат для List[Id]
  2. При чтении или записи, используйте формат для Id
  3. При чтении используйте
def flatten[T](xs: Seq[JsResult[T]]): JsResult[List[T]] = {
  val (ss: Seq[JsSuccess[T]], fs: Seq[JsError]) = xs.partition(_.isSuccess)
  if (fs.isEmpty) JsSuccess(ss.map(_.get).toList) else fs.head
}

1 Ответ

0 голосов
/ 18 февраля 2020

Если play JSON имеет автоматический / полуавтоматический c код c производных экземпляров, то он будет использовать неявный для включения такого механизма. Это означает, что кодеки для сложных вещей должны быть введены после их компонентов.

В вашем случае, похоже, что play JSON пытается получить код c для List как для класса case, т.е. как для List(a1, List(a2, ..., List(an, Nil))), и когда он достигает Nil, он не знает, как выведите код c для этого.

Я полагаю, вы хотите, чтобы ваш список был закодирован не как цепочка свернутых объектов, а как массив JSON.

Тогда вам следует поискать источники воспроизведения по умолчанию List[T] код c и попробуйте использовать его, специализируя его для Id.

Общим инструментом для отладки отсутствующих имплицитов является опция компилятора "-Xlog-implicits". Он будет регистрировать все неудачные неявные поиски на консоли, и можно выяснить, чего не хватает в этих сообщениях.

Также настоятельно рекомендуется знать , как неявно работает, прежде чем работать с библиотеками, которые широко используют этот feautre.

И последнее, но не менее важное:

Вы когда-нибудь пробовали использовать circe ? Он имеет автоматов c и полуавтоматических c JSON дериваций для семейств запечатанных признаков и стандартных scala классов. Он даже имеет интеграцию с игровой платформой. Деривация Circe устраняет большую часть головной боли при написании кода c, но для правильной работы требуется глубокое знание неявного приоритета Как это работает, описано здесь и здесь .

Вы также можете попытаться создать свой собственный вывод для игры - json, если нет подходящего стандартного варианта с Morphling .

...