是否可以在自定义序列化程序中序列化为已知的默认格式?
Is it possible to serialize as known default format in custom serializer?
我必须反序列化 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 个字段,因此它会导致相当混乱且难以阅读的代码。所以我想知道是否有更好的方法来做到这一点,因为 FirstItem
和 SecondItem
都可以仅使用 DefaultFormats
进行反序列化。有什么方法可以告诉 Json4s,如果对象匹配给定的类型,则应该使用默认格式对其进行序列化?
我深入研究了各种示例,结果证明这是可行的,而且非常简单。有一个 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)
}
我必须反序列化 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 个字段,因此它会导致相当混乱且难以阅读的代码。所以我想知道是否有更好的方法来做到这一点,因为 FirstItem
和 SecondItem
都可以仅使用 DefaultFormats
进行反序列化。有什么方法可以告诉 Json4s,如果对象匹配给定的类型,则应该使用默认格式对其进行序列化?
我深入研究了各种示例,结果证明这是可行的,而且非常简单。有一个 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)
}