json4s,如何使用 Full TypeHints w/o 显式设置 Type Hints 反序列化 json

json4s, how to deserialize json with FullTypeHints w/o explicitly setting TypeHints

我在反序列化之前指定了 FullTypeHints

 def serialize(definition: Definition): String = {
    val hints = definition.tasks.map(_.getClass).groupBy(_.getName).values.map(_.head).toList
    implicit val formats = Serialization.formats(FullTypeHints(hints))
    writePretty(definition)
  }

它生成带有类型提示的 json,太棒了!

{
  "name": "My definition",
  "tasks": [
    {
      "jsonClass": "com.soft.RootTask",
      "name": "Root"
    }
  ]
}

反序列化不起作用,它会忽略类型为 hint

的 "jsonClass" 字段

  def deserialize(jsonString: String): Definition = {
    implicit val formats = DefaultFormats.withTypeHintFieldName("jsonClass")
    read[Definition](jsonString)
  }

如果提示在 json 字符串中,为什么我应该使用 Serialization.formats(FullTypeHints(hints)) 重复 typeHints 进行反序列化?

json4s 可以从 json 推断出它们吗?

反序列化器并没有忽略类型提示字段名称,它只是没有任何东西可以映射它。这就是提示的用武之地。因此,您必须再次声明并分配您的提示列表对象,并通过使用 withHints 方法或在创建 DefaultFormats 的新实例时覆盖该值将其传递给 DefaultFormats 对象。下面是使用后一种方法的示例。

val hints = definition.tasks.map(_.getClass).groupBy(_.getName).values.map(_.head).toList
implicit val formats: Formats = new DefaultFormats {
    outer =>
        override val typeHintFieldName = "jsonClass"
        override val typeHints = hints
}

因为我有合同所以我这样做了:

  • withTypeHintFieldName提前知道
  • withTypeHintFieldName 包含完全限定的 class 名称,并且总是大小写 class
def deserialize(jsonString: String): Definition = {
    import org.json4s._
    import org.json4s.native.JsonMethods._
    import org.json4s.JsonDSL._
    val json = parse(jsonString)
    val classNames: List[String] = (json \ $$definitionTypes$$ \ classOf[JString])
    val hints: List[Class[_]] = classNames.map(clz => Try(Class.forName(clz)).getOrElse(throw new RuntimeException(s"Can't get class for $clz")))

    implicit val formats = Serialization.formats(FullTypeHints(hints)).withTypeHintFieldName($$definitionTypes$$)
    read[Definition](jsonString)