组合类型和字段序列化器 [英] Combining type and field serializers

查看:102
本文介绍了组合类型和字段序列化器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个具有以下设置的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似乎具有只能在特定字段上起作用的字段序列化程序,其中包括样板方法,可以轻松地转换名称和丢弃字段.但是,它们的serializedeserialize部分功能具有以下签名:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆