spray-json:序列化通用特征



spray-json依赖于在T实例上调用toJson时存在范围内的隐式JsonWriter[T]

假设我有一个具有几个具体子类型的特征,每个子类型都有一个 JsonWriter:

trait Base
case class Foo(a: Int) extends Base
case class Bar(a: Int, b: Int) extends Base
implicit val FooFormat = jsonFormat1(Foo)
implicit val BarFormat = jsonFormat2(Bar)
def go(o: Base) = {
    o.toJson
}

go 无法编译,因为没有用于 Base 的 JsonWriter,即使所有具体子类型都有编写器。

如何重新组织此代码,以便Base的泛型函数使用适当的 json 格式化程序?

可以使用具有类型和上下文边界的泛型方法。喜欢这个:

def go[T <: Base : JsonWriter](t: T) = t.toJson

编组Base需要JsonFormat。以下是解决所述问题的方法之一。

import spray.json._
object BaseJsonProtocol extends DefaultJsonProtocol {
  implicit val FooFormat = jsonFormat1(Foo)
  implicit val BarFormat = jsonFormat2(Bar)
  implicit object BaseJsonFormat extends RootJsonFormat[Base] {
    def write(obj: Base) = obj match {
      case x: Foo ⇒ x.toJson
      case y: Bar ⇒ y.toJson
      case unknown @ _ => serializationError(s"Marshalling issue with ${unknown}")
    }
    def read(value: JsValue) = {
      value.asJsObject.getFields("a","b") match {
        case Seq(JsNumber(a)) => Foo(a.toInt)
        case Seq(JsNumber(a), JsNumber(b)) => Bar(a.toInt, b.toInt)
        case unknown @ _ => deserializationError(s"Unmarshalling issue with ${unknown} ")
    }
  }
 }
}

因此,BaseJsonProtocol可用于封送Base实例,如下所示。

import BaseJsonProtocol._
def go(o: Base) =  o.toJson
assert (go(Foo(10)).convertTo[Foo] == Foo(10))
assert (go(Foo(10).asInstanceOf[Base]).convertTo[Foo] == Foo(10))
assert (go(Bar(10,100)).convertTo[Bar] == Bar(10, 100))

希望对您有所帮助!

我意识到一种解决方案是将go设置为具有类型绑定的泛型函数,并"显式"声明隐式值..."

def go[T <: Base](t: T)(implicit fmt: JsonWriter[T]) =
    t.toJson

现在函数可以编译,因为JsonWriter被承诺为函数参数,并且每个调用站点都可以根据上下文(FooFormatBarFormat)拉入JsonWriter[T]的具体实现。

最新更新