json4s, как десериализовать json с FullTypeHints без явной установки TypeHints - PullRequest
1 голос
/ 04 апреля 2020

Я указываю 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"
    }
  ]
}

Десериализация не работает, она игнорирует поле "jsonClass" с подсказкой типа


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

Почему я должен повторять typeHints, используя Serialization.formats(FullTypeHints(hints)) для десериализации, если подсказки находятся в json строке?

Может ли json4s выводить их из json?

Ответы [ 2 ]

1 голос
/ 05 апреля 2020

Я сделал это так, поскольку у меня есть контракт:

  • withTypeHintFieldName известен заранее
  • withTypeHintFieldName содержит полное имя класса, и это всегда регистр класса
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)
1 голос
/ 04 апреля 2020

Десериализатор не игнорирует имя поля подсказки типа, просто ему не с чем сопоставить его. Именно здесь появляются подсказки. Таким образом, вы должны еще раз объявить и назначить объект списка подсказок и передать его объекту DefaultFormats либо с помощью метода withHints, либо переопределив значение при создании нового экземпляра 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
}
...