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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 05:59:11  来源:igfitidea点击:

how to serialize case classes with traits with jsonspray

scalasprayspray-json

提问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)

Source

来源

Option 2

选项 2

Another option is to supply implicit jsonFormats for Personand any other subclasses of Animaland then write your serialize code like so:

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

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

Source

来源

回答by eranga

It can be done with extending RootJsonFormat. An examples can be found from here.

它可以通过扩展来完成RootJsonFormat。可以从此处找到示例。

回答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)))
    }
  }