我们有一个现有的类A
,它以前是唯一可以出现在REST API端点的JSON输出中的某个位置的类型。然而,我现在使它扩展一个公共基类B
,以便一系列不同的类型,都继承自B
,可以出现在输出的那个位置。
我向Formats
添加了一个类型提示,但是即使Formats
方法在两个方向上都正确地查找了类型提示信息,类型提示在lift-json的序列化中被忽略了。
原来lift-json没有添加类型提示字段的原因是在我们的Formats
实例中为该类配置了一个自定义序列化器,并且自定义序列化器覆盖类型提示。
那么,我们如何让一个类既拥有自定义序列化器,又发出和产生类型提示,以允许(在客户端和服务器端)明确标识其类型呢?
这已经不是很好的文档了,但是TypeHints
特性有两个方法:
def deserialize: PartialFunction[(String, JObject), Any] = Map()
def serialize: PartialFunction[Any, JObject] = Map()
这些方法可以在实现TypeHints
trait(或扩展TypeHints
提供的默认实现)时被覆盖,以指定具有指定类型提示的JSON对象的自定义序列化和反序列化逻辑。默认实现(如上所示)实际上只是部分函数,永远不会匹配任何内容,因此它们没有任何效果。
与Serializer
中的deserialize
和serialize
方法有一些不同,这是我们之前使用的代码:
这些方法不接受
Formats
参数,这意味着必须依赖范围内的Formats
实例。它们在JSON端的
JObject
上操作,而不是它的超类型JValue
(很明显,当你想到它时-因为任何有类型提示的东西都不可避免地必须是JSON对象,而不是字符串或数字或其他什么)。它们不接受类型参数,只在Scala的
Any
上进行转换——这是因为它们只在一个大的部分函数中处理所有需要自定义序列化逻辑的类型暗示类型。deserialize
部分函数不接受TypeInfo
,而接受String
,这是类型提示字段的值。
我认为这些差异大部分是因为这是较旧的lift-json代码,从Serializer
特性存在之前,当只有一种方法来做自定义序列化。
所以对我有用的是:
def typeHints(implicit formats: Formats) = new OurTypeHintsImpl(
…类型提示信息…) {
override def deserialize = {
case ("type-hint-for-A", o: JObject) =>
…现有反序列化代码…
}
override def deserialize = {
case A(
…) =>
……现有序列化代码…
}
和添加另一个具有类型提示和自定义序列化逻辑的类型,只需要在上述两个分支中添加一个新的case
分支。
使用这种方法,lift-json会自动添加正确的类型提示,但是您仍然可以完全自定义其余的序列化和反序列化是如何完成的。所以我认为这是大多数情况下最方便和合适的方法(但它确实需要一些重构)。在自定义Serializer
中也应该可以重新实现类型提示,但是为什么要重新发明轮子呢?
警告:默认情况下,类型上的大小写匹配对于泛型类型有限制,但这通常不应该影响此目的-除非您不是独立地序列化包含在另一个类型中的泛型类型,而是将其合并到JSON中的外部类型中。