Расширение AutoDerivation в Circe не работает - PullRequest
0 голосов
/ 10 июля 2019

Мой вопрос касается второго решения, предложенного mixel здесь: Scala Circe с генериками

Обратите внимание, что в текущей версии Circe черта с именем Auto in Circe была переименована в AutoDerivation.

Я использую решение mixel, предоставленное в его решении StackOverflow, но не смог заставить его работать. Я пытался обновить мою версию Circe до последней и убедиться, что плагин Macro Paradise импортирован, но все же не повезло.

Вот мой код. Первый - это собственный файл, который называется CirceGeneric.

import io.circe._
import io.circe.parser._
import io.circe.generic.extras._

object CirceGeneric {
  trait JsonEncoder[T] {
    def apply(in: T): Json
  }

  trait JsonDecoder[T] {
    def apply(s: String): Either[Error, T]
  }

  object CirceEncoderProvider {
    def apply[T: Encoder]: JsonEncoder[T] = new JsonEncoder[T] {
      def apply(in: T) = Encoder[T].apply(in)
    }
  }

  object CirceDecoderProvider {
    def apply[T: Decoder]: JsonDecoder[T] = new JsonDecoder[T] {
      def apply(s: String) = decode[T](s)
    }
  }
}

object Generic extends AutoDerivation {
  import CirceGeneric._

  implicit def encoder[T: Encoder]: JsonEncoder[T] = CirceEncoderProvider[T]
  implicit def decoder[T: Decoder]: JsonDecoder[T] = CirceDecoderProvider[T]

}

Второй - это метод для модульного тестирования, который использует функцию Akka responseAs. Этот метод появляется в классе BaseServiceTest.

  def responseTo[T]: T = {
    def response(s: String)(implicit d: JsonDecoder[T]) = {
      d.apply(responseAs[String]) match {
        case Right(value) => value
        case Left(error) => throw new IllegalArgumentException(error.fillInStackTrace)
      }
    }
    response(responseAs[String])
  }

Идея состоит в том, чтобы преобразовать результат responseAs [String] (который возвращает строку) в декодированный класс case.

Код не работает должным образом. Intellij не обнаруживает каких-либо пропущенных последствий, но когда приходит время компиляции, у меня возникают проблемы. Следует отметить, что файл BaseServiceTest содержит импорт для CirceGeneric._ и Generic._, поэтому пропущенная инструкция import не является проблемой.

[ошибка] [...] / BaseServiceTest.scala: 59: не удалось найти неявное значение для параметра d: [...] CirceGeneric.JsonDecoder [T] [ошибка] ответ (responseAs [String])

Либо неявное преобразование из декодера [T] в JsonDecoder [T] не происходит, либо экземпляр Decoder [T] не создается. В любом случае, что-то не так.

1 Ответ

1 голос
/ 10 июля 2019

Вам все еще нужен контекст Decoder или JsonDecoder, связанный с responseTo.

def responseTo[T : Decoder]: T = ...

Это потому, что весь ваш код, и действительно код микселя в связанном ответе, посвящен абстрагированию отот Decoder до черты JsonDecoder, которую можно использовать для межбиблиотечной поддержки.Но у вас до сих пор нет способа его создания без базового Decoder экземпляра.

Теперь есть несколько способов автоматического генерирования Decoder s для (например) классов case, содержащихся в circe.generics.auto, но на данный момент в вашем коде

def responseTo[T]: T = {
    def response(s: String)(implicit d: JsonDecoder[T]) = ...
    ...
}

вы просите компилятор предоставить неявный JsonDecoder (т. е. в вашей настройке, Decoder) экземпляр для любого произвольного типа,Как объясняет принятый ответ на связанный вопрос, это невозможно.

Вам необходимо отложить неявное разрешение до того момента, когда вы будете знать, с каким типом вы имеете дело - в частности, вы можете предоставить Decoder[T] экземпляр для него.

РЕДАКТИРОВАТЬ: В вашем ответе на ваш комментарий относительно смысла, если вы не можете создать JsonDecoder s для всех типов ...

Мое пониманиесвязанный вопрос заключается в том, что они пытаются абстрагировать библиотеку circe, чтобы разрешить замену реализации библиотеки JSON.Это делается следующим образом:

  • добавить класс типа JsonDecoder

  • иметь пакет json, который содержит импликации (используя Circe)для их автоматического создания с помощью объекта пакета с расширением AutoDerivation

  • внешний код относится только к JsonDecoder и импортирует импликации в пакет json

Тогда вся сериализация JSON и неявное разрешение работают без необходимости вызова кода для ссылки на io.circe, и при желании легко переключить json / JsonDecoder на другую библиотеку JSON.Но вам все равно придется использовать контекстную привязку JsonDecoder и ограничиваться работой с типами, для которых может быть создан такой неявный.Который не каждый тип.

...