用于蛇案例 ADT 的 ConfiguredJsonCodec

Posted

技术标签:

【中文标题】用于蛇案例 ADT 的 ConfiguredJsonCodec【英文标题】:ConfiguredJsonCodec for snake case ADT 【发布时间】:2020-12-08 12:39:46 【问题描述】:

我必须使用一个 json api,其中有一个蛇案例中的离散字符串值列表。

以下示例有效,但我想删除手动 fooDecoder 以支持(当前已注释掉的)ConfiguredJsonCodec 注释。

或更基本的问题:将这些离散值建模为 ADT 中的案例对象是否有意义,或者是否有其他方法?

import io.circe._
import io.circe.syntax._
import io.circe.generic.extras.Configuration, ConfiguredJsonCodec, JsonKey
import io.circe.parser.parse

implicit val jsonConfig: Configuration = Configuration.default
  .withSnakeCaseConstructorNames
  .withSnakeCaseMemberNames

//@ConfiguredJsonCodec(decodeOnly = true)
sealed trait Foo
object Foo 
  case object FooBar extends Foo
  case object FooBaz extends Foo
  case object FooWuz extends Foo


import Foo._
implicit val fooDecoder: Decoder[Foo] = new Decoder[Foo] 
  override def apply(c: HCursor) = c.as[String].map
    case "foo_bar" => FooBar
    case "foo_baz" => FooBaz
    case "foo_wuz" => FooWuz
  


@ConfiguredJsonCodec(decodeOnly = true)
case class Qux(fooFoo: List[Foo])

val input =""""foo_foo" : ["foo_bar", "foo_baz", "foo_wuz"]"""
val json: Json = parse(input).left.map(println(_)).right.get

json.as[Qux]

完整示例:https://scastie.scala-lang.org/eVFyNMGFRgaw9oEkRveT8g

这使用大约 0.13.0

【问题讨论】:

【参考方案1】:

所有 Circe 联产品派生方法都假定存在歧视字段,您最多可以选择它的名称。所以支持的格式是这样的:


  "type": "foo_bar",

而不仅仅是

"foo_bar"

原因是派生机制认为 case-object-only 和 case-object-and-case-classes 之间没有区别,所以对于这样的代码

trait MyADT
object MyADT 
  case class Value1(value: String) extends MyADT
  case class Value2(value: String) extends MyADT

您只需将 sum 部分的编解码器组合在一起

val decoder: Decoder[MyADT] = Decoder[Value1].widen orElse Decoder[Value2].widen

即使您对Value2 进行了编码,您也总是会首先解码为Value1。 Derivation 认为这两种情况之间没有区别,因此他们更愿意始终使用判别场来保证安全。 (这里是discussed in docs)。

但是,如果您知道自己正在构建枚举,则可以简单地使用带有 circe 支持的 enumeratum:

import enumeratum._

sealed trait Foo extends EnumEntry with Snakecase
object Foo extends Enum[Foo] with CirceEnum[Foo] 
  case object FooBar extends Foo
  case object FooBaz extends Foo
  case object FooWuz extends Foo

  val values = findValues

这将实现您的目标,尽管方式不同。

【讨论】:

谢谢。不幸的是,我对我使用的 json 格式没有影响。不过我会考虑使用 enumeratum。

以上是关于用于蛇案例 ADT 的 ConfiguredJsonCodec的主要内容,如果未能解决你的问题,请参考以下文章

面向对象案例——贪吃蛇游戏

在 jhipster 项目中将实体属性骆驼案例转换为 json 中的蛇案例

SIKI_Unity_2_初级案例_贪吃蛇

将 JSON 骆驼案例转换为蛇案例(反之亦然)并将数值字符串化

Python-pygame案例AI贪吃蛇

JavaScript面向对象游戏案例:贪吃蛇