12

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.

4

2 回答 2

11

现在在 json4s 的 extras 包中提供了一个 UUID 序列化器。它很可能在版本 3.2.11 中可用(在撰写本文时尚未发布)。

您将能够执行以下操作:

import org.json4s.ext.JavaTypesSerializers

implicit val json4sFormats = Serialization.formats(NoTypeHints) ++ JavaTypesSerializers.all

这是从对该功能的 PR 的测试中得出的

于 2014-08-26T17:37:27.053 回答
6

诀窍是不要为您的类型编写序列化程序,而是为您在内部使用的类型(在本例中为 java.util.UUID)编写序列化程序

然后,您可以将该序列化程序添加到工具箱中,然后使用 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
于 2014-06-01T08:07:42.567 回答