Circe Scala - кодировать и декодировать карту [] и тематические классы - PullRequest
0 голосов
/ 08 октября 2018

Я пытаюсь создать кодер и декодер для класса дел, который у меня есть:

case class Road(id: String, light: RoadLight, names: Map[String, String])

RoadLight - это класс java с enum.

public enum RoadLight {
red,yellow,green
}

Я пытался сделать полуавтоматическое кодирование и декодирование: создание неявных кодеров и декодеров.
Я начал с типа Map [String, String]:

implicit val namesDecoder: Decoder[Map[String, String]] = deriveDecoder[Map[String, String]]
implicit val namesEncoder: Encoder[Map[String, String]] = deriveEncoder[Map[String, String]]

Но я получил ошибку для них обоих!

1: не удалось найти неявное неявное значение типа io.circe.generic.decoding.DerivedDecoder [A]

2: Ошибка: недостаточно аргументов для метода DeriveDecoder: (неявное декодирование: shapeless.].Не указано значение параметра декодирования.неявный val namesDecoder: Decoder [Map [String, String]] = diverveDecoder

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

Есть идеи?Спасибо!

Ответы [ 2 ]

0 голосов
/ 09 октября 2018

circe-generic не создает кодеки для перечислений java, только для типов продуктов и сумм scala.Но откатить свой собственный за RoadLight не сложно.И как только вы это получите, вы получите карту.

Код ниже работает:

object RoadLightCodecs {
  implicit val decRl: Decoder[RoadLight] = Decoder.decodeString.emap {
    case "red" => Right(RoadLight.Red)
    case "yellow" => Right(RoadLight.Yellow)
    case "green" => Right(RoadLight.Green)
    case s => Left(s"Unrecognised traffic light $s")
  }

  implicit val encRl: Encoder[RoadLight] = Encoder.encodeString.contramap(_.toString)


  implicit val decodeMap = Decoder.decodeMap[String, RoadLight]
  implicit val encodeMap = Encoder.encodeMap[String, RoadLight]
}

Итак, мы сделали кодеки для основных типов, а затем использовали их для построениякодек карты большего размера.

Теперь, насколько мне известно, нет библиотек, которые бы делали это автоматически для java-перечислений, хотя теоретически должно быть возможно написать одну.Но использование комбинаторов на базовых кодеках для создания более сложных кодеков прекрасно работает и хорошо масштабируется.

РЕДАКТИРОВАТЬ: у меня была игра с автоматическим выводом кодеков java enum, и вы можете почти сделать это:

  def decodeEnum[E <: Enum[E]](values: Array[E]): Decoder[E] = Decoder.decodeString.emap { str =>
    values.find(_.toString.toLowerCase == str)
      .fold[Either[String, E]](Left(s"Value $str does not map correctly"))(Right(_))
  }

  def encodeEnum[E <: Enum[E]]: Encoder[E] =
    Encoder.encodeString.contramap(_.toString.toLowerCase)

  implicit val roadLightDecoder = decodeEnum[RoadLight](RoadLight.values())
  implicit val roadLightEncoder = encodeEnum[RoadLight]

Таким образом, encodeEnum может быть автоматическим (вы можете сделать его неявным вместо val в конце), но декодеру нужно дать значения (которые я не вижу способа получить автоматически из типа), поэтому вам нужно передать их при создании кодека.

0 голосов
/ 08 октября 2018

Скаладок говорит:

/**
 * Semi-automatic codec derivation.
 *
 * This object provides helpers for creating [[io.circe.Decoder]] and [[io.circe.ObjectEncoder]]
 * instances for case classes, "incomplete" case classes, sealed trait hierarchies, etc.

Map не является классом дел или элементом иерархии запечатанных признаков.

https://github.com/circe/circe/issues/216

Кодировать карту [String, MyCaseClass] в Seq [String, String] с использованием circe

Circe и тип перечисления Scala

...