组合类型和字段序列化器 [英] Combining type and field serializers
问题描述
假设我有一个具有以下设置的case类:
case class Place(id:java.util.UUID, name:String)
我可以为这种类型编写一个(有效的)序列化器,如下所示:
class placeSerializer extends CustomSerializer[Place]( format => (
{
case JObject(JField("id", JString(s)) :: JField("name",JString(x)) :: Nil ) =>
Place(UUID.fromString(s), x)
},
{
case x:Place =>
JObject(
JField("id", JString(x.id.toString())) ::
JField("name", JString(x.name)) :: Nil)
}
)
)
但是假设我的case类最终有更多的字段,这可能导致我用AST枚举对象的整个结构,从而创建了一个非常冗长的东西,仅用于编码基元.
json4s似乎具有只能在特定字段上起作用的字段序列化程序,其中包括样板方法,可以轻松地转换名称和丢弃字段.但是,它们的serialize
和deserialize
部分功能具有以下签名:
case class FieldSerializer[A: Manifest](
serializer: PartialFunction[(String, Any), Option[(String, Any)]] = Map(),
deserializer: PartialFunction[JField, JField] = Map()
)
由于JField
(代表json中的键-> val的类型)是它自己的类型,而不是JValue
的子类,因此我如何结合这两种类型的序列化程序来正确编码id
键,将其名称键入UUID
,同时保持其他字段(原始数据类型)的默认处理.
基本上,我希望格式链能够理解Place
中的字段是UUID,而不必为DefaultFormats
已经可以处理的所有字段指定AST结构.
我要寻找的是模仿与 JSONEncoder
类似的模式python中的JSONDecoder
接口,可以使用键名和值类型来确定如何处理字段的编组.
诀窍是不为您的类型编写序列化程序,而是为内部使用的类型(在本例中为java.util.UUID)编写序列化程序. /p>
然后,您可以将该序列化器添加到工具箱中,然后使用UUID的任何类型将与使用DefaultSerializer支持的字段的类型完全相同:
case object UUIDSerialiser extends CustomSerializer[UUID](format => (
{
case JString(s) => UUID.fromString(s)
case JNull => null
},
{
case x: UUID => JString(x.toString)
}
)
)
implicit val json4sFormats = Serialization.formats(NoTypeHints) + UUIDSerialiser
更新链接到 PR
更新2 ,PR已合并,现在,如果使用UUID,则可以使用:
import org.json4s.ext.JavaTypesSerializers
implicit val json4sFormats = Serialization.formats(NoTypeHints) ++ JavaTypesSerializers.all
Let's assume I have a case class with the following setup:
case class Place(id:java.util.UUID, name:String)
I can write a (working!) serializer for this type as follows:
class placeSerializer extends CustomSerializer[Place]( format => (
{
case JObject(JField("id", JString(s)) :: JField("name",JString(x)) :: Nil ) =>
Place(UUID.fromString(s), x)
},
{
case x:Place =>
JObject(
JField("id", JString(x.id.toString())) ::
JField("name", JString(x.name)) :: Nil)
}
)
)
But assuming my case class eventually has a lot more fields, this could lead to me enumerating the entire structure of the object with the AST, creating something that's very verbose just to encode primitives.
json4s appears to have field serializers that can act only on specific fields, with boilerplate methods included to easily transform names and discard fields. These, however, have the following signature for their serialize
and deserialize
partial functions:
case class FieldSerializer[A: Manifest](
serializer: PartialFunction[(String, Any), Option[(String, Any)]] = Map(),
deserializer: PartialFunction[JField, JField] = Map()
)
Since JField
(the type that representes a key -> val from the json) is its own type and not a subclass of JValue
, how can I combine these two types of serializers to properly encode the id
key by its name to a UUID
, while maintaining the default handling of the other fields (which are primitive datatypes).
Essentially I'd like a format chain that understands the field within Place
is a UUID, without having to specify AST structure for all the fields that DefaultFormats
can already handle.
What I'm looking for specifically is to mimic a pattern similar to the JSONEncoder
and JSONDecoder
interfaces in python, which can use the key name as well as value type to determine how to handle the marshalling for the field.
The trick is to not write a serializer for your type, but for the type that you're using inside (in this case java.util.UUID)
Then you can add that serializer to the toolbox and from then any type using UUID will work exactly like types using DefaultSerializer supported fields did:
case object UUIDSerialiser extends CustomSerializer[UUID](format => (
{
case JString(s) => UUID.fromString(s)
case JNull => null
},
{
case x: UUID => JString(x.toString)
}
)
)
implicit val json4sFormats = Serialization.formats(NoTypeHints) + UUIDSerialiser
Update link to the PR
Update 2 the PR was merged, and now, in case of UUID you can use:
import org.json4s.ext.JavaTypesSerializers
implicit val json4sFormats = Serialization.formats(NoTypeHints) ++ JavaTypesSerializers.all
这篇关于组合类型和字段序列化器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!