【问题标题】:circe type field not showingcirce 类型字段未显示
【发布时间】:2023-03-09 15:06:01
【问题描述】:

当使用 circe 编码为 Json 时,我们真的希望 type 字段显示例如

scala> val fooJson = foo.asJson
fooJson: io.circe.Json =
{
  "this_is_a_string" : "abc",
  "another_field" : 123,
  "type" : "Foo"
}

这取自之前提到您可以像这样配置编码的发行说明:

implicit val customConfig: Configuration = 
Configuration.default.withSnakeCaseKeys.withDefaults.withDiscriminator("type")

还有关于 circe here 的其他信息表明,在没有任何配置的情况下,您应该在编码 json 中获取一些类类型信息。

我错过了什么吗?如何让类类型显示?

【问题讨论】:

    标签: scala circe


    【解决方案1】:

    2017 年 3 月 30 日更新:跟进 OP 的评论

    我能够完成这项工作,如链接的release notes 所示。

    准备步骤1:向build.sbt添加额外的依赖

    libraryDependencies += "io.circe" %% "circe-generic-extras" % "0.7.0"
    

    准备步骤 2:设置虚拟密封特征层次结构

    import io.circe.{ Decoder, Encoder }
    import io.circe.parser._, io.circe.syntax._
    import io.circe.generic.extras.Configuration
    import io.circe.generic.extras.auto._
    import io.circe.generic.{ semiauto => boring } // <- This is the default generic derivation behaviour
    import io.circe.generic.extras.{ semiauto => fancy } // <- This is the new generic derivation behaviour
    
    implicit val customConfig: Configuration = Configuration.default.withDefaults.withDiscriminator("type")
    
    sealed trait Stuff
    case class Foo(thisIsAString: String, anotherField: Int = 13) extends Stuff
    case class Bar(thisIsAString: String, anotherField: Int = 13) extends Stuff
    
    object Foo {
      implicit val decodeBar: Decoder[Bar] = fancy.deriveDecoder
      implicit val encodeBar: Encoder[Bar] = fancy.deriveEncoder
    }
    
    object Bar {
      implicit val decodeBar: Decoder[Bar] = boring.deriveDecoder
      implicit val encodeBar: Encoder[Bar] = boring.deriveEncoder
    }
    

    使用这个的实际代码:

    val foo: Stuff = Foo("abc", 123)
    val bar: Stuff = Bar("xyz", 987)
    
    val fooString = foo.asJson.noSpaces
    // fooString: String = {"thisIsAString":"abc","anotherField":123,"type":"Foo"}
    
    val barString = bar.asJson.noSpaces
    // barString: String = {"thisIsAString":"xyz","anotherField":987,"type":"Bar"}
    
    val bar2 = for{
      json <- parse(barString)
      bar2 <- json.as[Stuff]
    } yield bar2
    // bar2: scala.util.Either[io.circe.Error,Stuff] = Right(Bar(xyz,987))
    
    val foo2 = for{
      json <- parse(fooString)
      foo2 <- json.as[Stuff]
    } yield foo2
    // foo2: scala.util.Either[io.circe.Error,Stuff] = Right(Foo(abc,123))
    

    因此,只要您导入额外的依赖项(这是 Configuration 的来源),它看起来就可以工作。

    最后,作为旁注,Circe's DESIGN.md 和练习之间似乎确实存在一些脱节,对此我实际上很高兴。


    原答案: 我不确定这是否应该被设计支持。

    取自Circe's DESIGN.md

    不应使用隐式作用域进行配置。很多人都要求提供一种方法来配置通用编解码器派生以使用例如类型字段作为密封特征层次结构的鉴别器,或使用蛇形大小写作为成员名称。 argonaut-shapeless 使用用户可以隐式提供的 JsonCoproductCodec 类型非常直接地支持这一点。

    我不想批评这种方法——它完全是惯用的 Scala,而且在实践中通常效果很好——但我个人不喜欢使用隐式值进行配置,我想避免它直到我 100% 确信没有其他方法可以提供此功能。

    这具体意味着什么:您可能永远不会看到不是类型类实例的隐式参数 - 即这不是应用于模型中的类型的类型构造函数——大约,通用编解码器派生的配置将相对有限(与例如 argonaut-shapeless 相比),直到我们找到一种很好的方法来做这种事情带有类型标签或类似的东西。

    特别是,customConfig: Configuration 似乎正是最后一段引用的参数类型(例如,一个不是类型类实例的隐式参数

    我相信@travis-brown 或任何其他 Circe 的主要贡献者可以对此有所了解,以防实际上有办法做到这一点 - 我很高兴知道它! :)

    【讨论】:

    • 看起来可能已经被取消了。上面提到的发行说明声明这是您配置它的方式:github.com/circe/circe/releases/tag/v0.6.0-RC1
    • 感谢您的更新 - 这是我发现的内容,您抢先回答。需要注意的一件事是,在我的情况下,我必须拥有import io.circe.generic.extras.auto._,即在范围内包含“附加”,否则它将不起作用。
    猜你喜欢
    • 2019-09-18
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-28
    • 2011-02-14
    • 1970-01-01
    • 2019-12-27
    相关资源
    最近更新 更多