20

我明白,如果我有:

case class Person(name: String)

我可以用

object PersonJsonImplicits extends DefaultJsonProtocol {
  implicit val impPerson = jsonFormat1(Person)
}

并因此将其序列化:

import com.example.PersonJsonImplicits._
import spray.json._
new Person("somename").toJson

但是如果我有

trait Animal
case class Person(name: String) extends Animal

我的代码中有某个地方

val animal = ???

我需要序列化它,我想使用 json spray

我应该添加哪个序列化程序我希望有类似的东西:

object AnimalJsonImplicits extends DefaultJsonProtocol {
  implicit val impAnimal = jsonFormat???(Animal)
}

也许我需要添加一些匹配器来检查什么类型是动物,这样如果它是一个人,我会将它定向到人但什么也没找到......正在阅读https://github.com/spray/spray-json 而且不明白该怎么做..

那么我怎样才能序列化这组

trait Animal
case class Person(name: String) extends Animal

用json喷雾?

4

2 回答 2

28

你有几个选择:

选项1

扩展RootJsonFormat[Animal]并放置您的自定义逻辑以匹配不同类型的Animal

import spray.json._
import DefaultJsonProtocol._

trait Animal   
case class Person(name: String, kind: String = "person") extends Animal

implicit val personFormat = jsonFormat2(Person.apply)   
implicit object AnimalJsonFormat extends RootJsonFormat[Animal] {
  def write(a: Animal) = a match {
    case p: Person => p.toJson
  }
  def read(value: JsValue) = 
    // If you need to read, you will need something in the 
    // JSON that will tell you which subclass to use
    value.asJsObject.fields("kind") match {
      case JsString("person") => value.convertTo[Person]
    }
}

val a: Animal = Person("Bob")
val j = a.toJson
val a2 = j.convertTo[Animal]

如果将此代码粘贴到 Scala REPL 中,则会得到以下输出:

a: Animal = Person(Bob,person)
j: spray.json.JsValue = {"name":"Bob","kind":"person"}
a2: Animal = Person(Bob,person)

资源

选项 2

另一种选择是为和任何其他子类提供隐式jsonFormats ,然后像这样编写序列化代码:PersonAnimal

def write(a: Animal) = a match {
  case p: Person => p.toJson
  case c: Cat => c.toJson
  case d: Dog => d.toJson
}

资源

于 2014-01-09T14:05:03.033 回答
0

可以通过扩展来完成RootJsonFormat。可以从这里找到一个示例。

于 2019-07-28T16:24:49.840 回答