是否可以在自定义序列化程序中序列化为已知的默认格式?

问题描述 投票:1回答:1

我必须反序列化JSON响应,该响应可以将字段之一设置为不同的对象(只有一个公共字段)。现实生活中的模型相当复杂,但例如,我们可以通过扩展密封特征的两个案例类来表示它:

sealed trait Item {
  val itemType: String
}

case class FirstItem(
  itemType: String = "FirstItem",
  firstProperties: SomeComplexType
) extends Item

case class SecondItem(
  itemType: String = "SecondItem",
  secondProperties: SomeOtherComplexType,
  secondName: String,
  secondSize: Int
) extends Item

由于Json4s不知道如何处理该对象,所以我编写了自定义序列化程序:

object ItemSerializer extends CustomSerializer[Item](_ => ({
  case i: JObject => 
    implicit val formats: Formats = DefaultFormats
    (i \ "itemType").extract[String] match {
      case "FirstType" => i.extract[FirstItem]
      case "SecondItem" => i.extract[SecondItem]
    }
}, {
  case x: Item => x match {
    case f: FirstItem => JObject() //TODO
    case s: SecondItem => JObject() //TODO
  }
}))

第一部分-反序列化并不是完美的,因为它很大程度上取决于类型字段,但是对于我的需求而言,它是很好的。问题是第二部分-序列化。在示例中,我发现人们通常会逐步记录每个字段,但是通常,他们会序列化一些简单的对象。在我的情况下,该对象具有多个级别,总共超过60-80个字段,因此将导致混乱且难以阅读代码。所以我想知道是否有更好的方法,因为FirstItemSecondItem都可以仅使用DefaultFormats进行反序列化。是否可以告诉Json4s如果对象与给定类型匹配,则应使用默认格式对其进行序列化?

scala json4s
1个回答
0
投票

我花了很多时间在各种示例中进行挖掘,结果证明这是可能的,而且非常简单。有org.json4s.Extraction.decompose()方法可以处理所有内容,例如:

object ItemSerializer extends CustomSerializer[Item](_ => ({
  case i: JObject => 
    implicit val formats: Formats = DefaultFormats
    (i \ "itemType").extract[String] match {
      case "FirstType" => i.extract[FirstItem]
      case "SecondItem" => i.extract[SecondItem]
    }
}, {
  case x: Item => 
    implicit val formats: Formats = DefaultFormats
    x match {
      case f: FirstItem => Extraction.decompose(f)
      case s: SecondItem => Extraction.decompose(s)
    }
}))

但是,我对所描述问题的解决方案是错误的。我不需要指定额外的序列化器。我需要的只是trait的一个伴随对象,其中包含每种数据格式的构造函数,而Json4s可以完美地处理所有事情,例如:]

object Item{
  def apply(
    itemType: String, 
    firstProperties: SomeComplexType
  ): Item = FirstItem(itemType, firstProperties)

  def apply(
    itemType: String, 
    secondProperties: SomeOtherComplexType, 
    secondName: String, secondSize: Int
  ): Item = SecondItem(itemType, secondProperties, secondName, secondSize)
}
© www.soinside.com 2019 - 2024. All rights reserved.