【问题标题】:How to serialize a nested (generic) case class如何序列化嵌套(通用)案例类
【发布时间】:2021-01-26 16:19:58
【问题描述】:

寻找一些关于使用 json4s 序列化嵌套案例对象的帮助。皱纹是 case 对象是在运行时决定的,所以看来我需要访问外部格式化程序?例如

trait Base { val id: Long }
case class ChildA(id: Long, name:String) extends Base
case class ChildB(id: Long, name:String) extends Base
case class WithTimestamp[E <: Base](base:E, timestamp:Long)

现在,如果我序列化我得到的 WithTimestamp,例如

{"base":{"id":1, "name":"foo"}, timestamp:12345 }

但我想得到的是:

{"id":1, "name":"foo", timestamp:12345 }

这似乎需要自定义序列化程序:

class WithTimestampSerializer[E <: Base] extends CustomSerializer[WithTimestamp[E]](
  f => ( {
    case x: JObject => ... 

  }, {
    case x: WithTimestamp[E] =>
    val j: JValue = write(x.base) // <--- not sure what to do at this point,
                                  // i.e. write either the ChildA or ChildB default serialization
      j merge JObject("timestamp" -> JLong(x.timestamp))
  }))

此时我如何访问应该可用的格式化程序?

【问题讨论】:

  • 我想你想使用 Extraction.decompose(x.base)。您可能可以跳过差异并将WithTimestamp[E] 替换为WithTimestamp[_]。我还会考虑更改/创建用于提供数据的模型。从长远来看可能比自定义格式化程序更简单。
  • 谢谢,这很有帮助,但这仍然将我标记为需要隐式格式化程序,这似乎只是将问题推回了 1 级。添加一个隐式格式化程序会给我一个堆栈溢出,obv。创建某种循环引用。
  • 哦,你需要像implicit val formats = org.json4s.DefaultFormats + new WithTimestampSerializer 这样的东西对你的序列化程序可见。或者您可以将 f 传递给 decompose(...)(f) 而不是使用隐式。
  • 成功了,谢谢
  • @TomerShetah 我考虑过并添加了答案:)

标签: scala json4s


【解决方案1】:

序列化程序如下所示:

class WithTimestampSerializer extends CustomSerializer[WithTimestamp[_]](
  f => ( {
    case x: JObject => ???
  }, {
    case x: WithTimestamp[_] =>
      val j: JValue = Extraction.decompose(x.base)(f) // <- the important part
      j merge JObject("timestamp" -> JLong(x.timestamp))
  }))

您可以使用 Extraction.decompose(x.base)(f) 或在附近使用 Format 类型的隐式。

但是,如果您想要反序列化它或扩展项目,我建议您添加一个新的案例类,仅用于对 JSON 数据进行建模。它增加了一些重复,但更容易维护。

【讨论】:

    猜你喜欢
    • 2013-10-12
    • 2019-08-11
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多