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

Doe*_*Doe 5 scala circe

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

case class Road(id: String, light: RoadLight, names: Map[String, String])
Run Code Online (Sandbox Code Playgroud)

RoadLight 是一个 java 类,带有枚举。

public enum RoadLight {
red,yellow,green
}
Run Code Online (Sandbox Code Playgroud)

我尝试过进行半自动编码和解码:制作隐式编码器和解码器。
我从 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]]
Run Code Online (Sandbox Code Playgroud)

但我确实得到了他们两个的错误!

1: 找不到 io.circe.generic.decoding.DerivedDecoder[A] 类型的 Lazy 隐式值

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

我已经按照书本做了一切,无法理解出了什么问题。我什至没有尝试解析案例类,只是解析地图,甚至这也不起作用。

有任何想法吗?谢谢!

tri*_*rNZ 5

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]
}
Run Code Online (Sandbox Code Playgroud)

因此,我们所做的是为基本类型制作编解码器,然后使用它们来构建更大的地图编解码器。

现在据我所知,没有任何库可以自动为 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]
Run Code Online (Sandbox Code Playgroud)

所以encodeEnum可以是自动的(你可以让它隐式而不是最后的val)但是解码器需要给出值(我认为没有办法从类型中自动获取),所以你需要在创建时传递这些值编解码器。


Dmy*_*tin 4

斯卡拉多克 说

/**
 * 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.
Run Code Online (Sandbox Code Playgroud)

Map不是密封特征层次结构的案例类或元素。

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

使用 circe 将 Map[String, MyCaseClass] 编码为 Seq[String, String]

Circe 和 Scala 的枚举类型