scala - 使用自定义 JsonFormats 进行喷雾路由中的喷雾 json 序列化

标签 scala spray spray-json

将 Spray 与 spray-json 用于系统,版本:

"io.spray" %% "spray-json" % "1.2.6"

我无法弄清楚如何让自定义 JsonFormat 定义用于由喷雾路由处理的序列化。

我有两种不同的情况都失败了。

1. 嵌套案例类

基本案例类 JSON 序列化工作正常
case class Something(a: String, b: String)
implicit val something2Json = jsonFormat3(Something)

但是,如果我在要序列化的案例类中有一个嵌套的案例类,我可以通过提供另一个隐式 JsonFormat 来解决编译问题,但在运行时它拒绝序列化
case class Subrecord(value: String)
case class Record(a: String, b: String, subrecord: Subrecord)

object MyJsonProtocol extends DefaultJsonProtocol {
  implicit object SubrecordJsonFormat extends JsonFormat[Subrecord] {
    def write(sub: Subrecord) = JsString(sub.value)
    def read(value: JsValue) = value match {
      case JsString(s) => Subrecord(s)
      case _ => throw new DeserializationException("Cannot parse Subrecord")
    }
  }

  implicit val record2Json = jsonFormat3(Record)
}

这将在运行时抛出 MappingException,说明子记录没有可用的值

2. 具有各种 0-N 大小写扩展的特征

在这里,我有一个特征作为一组案例类的捕获类型。一些扩展类有 vals,而另一些没有 vals 并且是对象。当序列化发生时,似乎我隐式定义的 JsonFormat 被完全忽略了,我只是给出了一个空的 JsObject,特别是当实际的基础类型是没有 val 的 case 对象之一时。
sealed trait Errors
sealed trait ErrorsWithReason extends Errors {
  def reason: String
}

case class ValidationError(reason: String) extends ErrorsWithReason
case object EntityNotFound extends Errors
case class DatabaseError(reason: String) extends ErrorsWithReason

object MyJsonProtocol extends DefaultJsonProtocol {
  implicit object ErrorsJsonFormat extends JsonFormat[Errors] {
    def write(err: Errors) = failure match {
      case e: ErrorsWithReason => JsString(e.reason)
      case x => JsString(x.toString())
    }
    def read(value: JsValue) = {
      value match {
        //Really only intended to serialize to JSON for API responses
        case _ => throw new DeserializationException("Can't reliably deserialize Error")
      }
    }
  }
}

因此,鉴于上述情况,如果被序列化的实际类型是 EntityNotFound,那么序列化就变成了 RootJsonFormat 变成了 {} .如果它是一个 ErrorsWithReason 那么它变成一个 RootJsonFormat 变成 { "reason": "somevalue" } .我可能对 JsonFormat 定义应该如何工作感到困惑,但它似乎根本没有使用我的 write 方法,而是突然想出了如何自行序列化。

编辑

特定的序列化案例正在使用读取/反序列化,例如:
entity(as[JObject]) { json =>
  val extraction: A = json.extract[A]
}

并使用 complete 写入/序列化指示。

由于这里发布的第一个答案,我现在意识到我的 JsonDefaultProtocol 和 JsonFormat 实现是针对spray-json 类的,同时反序列化中的实体指令提取使用的是json4s JObject,而不是spray-json JsObject。

最佳答案

清洁 JSON 输出的另一种方法

  import spray.json._
  import spray.json.DefaultJsonProtocol._

  // #1. Subrecords
  case class Subrecord(value: String)
  case class Record(a: String, b: String, subrecord: Subrecord)

  implicit object RecordFormat extends JsonFormat[Record] {
    def write(obj: Record): JsValue = {
      JsObject(
        ("a", JsString(obj.a)),
        ("b", JsString(obj.b)),
        ("reason", JsString(obj.subrecord.value))
      )
    }

    def read(json: JsValue): Record = json match {
      case JsObject(fields)
        if fields.isDefinedAt("a") & fields.isDefinedAt("b") & fields.isDefinedAt("reason") =>
          Record(fields("a").convertTo[String],
            fields("b").convertTo[String],
            Subrecord(fields("reason").convertTo[String])
          )

      case _ => deserializationError("Not a Record")
    }

  }


  val record = Record("first", "other", Subrecord("some error message"))
  val recordToJson = record.toJson
  val recordFromJson = recordToJson.convertTo[Record]

  println(recordToJson)
  assert(recordFromJson == record)

关于scala - 使用自定义 JsonFormats 进行喷雾路由中的喷雾 json 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25922464/

相关文章:

scala - 标记类型与类扩展 AnyVal

scala - 如何使 Scalatest 与 Spraytestkit 和 HttpServiceActor 一起工作

scala - 无法执行喷涂示例| Maven依赖错误

scala - 无法将 unicode 符号转换为西里尔字母

scala - 用Spray-json处理默认值的好方法是什么

Scala:流上的 filter 和 takeWhile 有什么区别?

scala - 无法让 sbt-concat 捆绑来自 sbt-sass 或 sbt-less 的样式

java - sbt 运行正常但运行 jar 失败

xml - 如何解码 Spray 中的案例类列表

scala - spray-json:序列化一个通用特征