Circe Scala-编码和解码Map []和案例类别

时间:2018-10-08 17:59:23

标签: scala circe

我正在尝试为我拥有的案例类创建编码器和解码器:

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

RoadLight是一个带有枚举的Java类。

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]的Lazy隐式值

2:错误:方法deriveDecoder的参数不足:(隐式解码:shapeless.Lazy [io.circe.generic.decoding.DerivedDecoder [A]])io.circe.Decoder [A ]。 未指定的值参数解码。   隐式val名称解码器:Decoder [Map [String,String]] = generateDecoder

我已经完成了本书的所有工作,无法理解出了什么问题。我什至不尝试解析case类,仅分析地图,即使这样也不起作用。

有什么想法吗?谢谢!

2 个答案:

答案 0 :(得分:2)

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枚举编解码器方面发挥了作用,您可以几乎做到这一点:

  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的末尾),但是需要为解码器提供值(我认为无法自动从类型中获取值),因此您需要传递创建编解码器时的内容。

答案 1 :(得分:0)

斯卡拉多克说

/**
 * 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

Encode Map[String, MyCaseClass] into Seq[String, String] using circe

Circe and Scala's Enumeration type