scala 如何使用 jsonspray 序列化具有特征的案例类
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20946701/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to serialize case classes with traits with jsonspray
提问by Jas
I understand that if I have:
我明白,如果我有:
case class Person(name: String)
I can use
我可以用
object PersonJsonImplicits extends DefaultJsonProtocol {
implicit val impPerson = jsonFormat1(Person)
}
and thus serialize it with:
并将其序列化为:
import com.example.PersonJsonImplicits._
import spray.json._
new Person("somename").toJson
however what If i have
但是如果我有
trait Animal
case class Person(name: String) extends Animal
and I have somewhere in my code
我的代码中有某处
val animal = ???
and I need to serialize it and I want to use json spray
我需要序列化它,我想使用 json Spray
which serializer should I add I was hoping to have something like:
我应该添加哪个序列化程序我希望有类似的东西:
object AnimalJsonImplicits extends DefaultJsonProtocol {
implicit val impAnimal = jsonFormat???(Animal)
}
where maybe I needed to add some matcher in order to check of what type is Animal so that if its a person I would direct it to person but found nothing... was reading https://github.com/spray/spray-jsonand don't understand how to do that..
也许我需要添加一些匹配器以检查什么类型是 Animal 以便如果它是一个人我会将它指向人但什么也没找到......正在阅读https://github.com/spray/spray-json并且不明白该怎么做..
so how can I serialize the set of
那么我该如何序列化一组
trait Animal
case class Person(name: String) extends Animal
with json spray?
用json喷雾?
回答by theon
You have a couple options:
你有几个选择:
Option 1
选项1
Extend RootJsonFormat[Animal]and put your custom logic for matching different types of Animal:
扩展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]
If you paste this code into the Scala REPL you get this output:
如果将此代码粘贴到 Scala REPL 中,则会得到以下输出:
a: Animal = Person(Bob,person)
j: spray.json.JsValue = {"name":"Bob","kind":"person"}
a2: Animal = Person(Bob,person)
Option 2
选项 2
Another option is to supply implicit jsonFormats for Personand any other subclasses of Animaland then write your serialize code like so:
另一种选择是jsonFormat为Person和 的任何其他子类提供隐式s Animal,然后像这样编写序列化代码:
def write(a: Animal) = a match {
case p: Person => p.toJson
case c: Cat => c.toJson
case d: Dog => d.toJson
}
回答by eranga
回答by Alex Elkin
You can add some extra field eq. typewhen serializing and use it to determine trait implementation when deserializing:
您可以添加一些额外的字段 eq。type序列化时使用它来确定反序列化时的特征实现:
trait Animal
case class Person(name: String) extends Animal
case class Lion(age: Int) extends Animal
implicit def personFormat = jsonFormat1(Person)
implicit def lionFormat = jsonFormat1(Lion)
implicit def animalFormat =
new RootJsonFormat[Animal] {
override def read(json: JsValue): Animal =
json.asJsObject.fields.get("type") match {
case Some(JsString("person")) => json.convertTo[Person]
case Some(JsString("lion")) => json.convertTo[Lion]
case t => deserializationError(s"Unable to deserialize Animal of type $t")
}
override def write(obj: Animal): JsValue =
obj match {
case e: Person => toJson(e, "person")
case e: Lion => toJson(e, "lion")
}
def toJson[T](obj: T, objType: String)(implicit w: JsonWriter[T]): JsObject = {
val o = obj.toJson.asJsObject
o.copy(fields = o.fields + ("type" -> JsString(objType)))
}
}

