自定义 spray-json RootJsonFormat 或 JsonFormat 取决于 JSON 对象中的值

Custom spray-json RootJsonFormat or JsonFormat depending on value in JSON object

在 Akka 流连接中,我收到 JSON 个如下所示的对象:

{"op":"connection"...}
{"op":"status"...}
..etc

我有以下 类 设置:

case class ResponseMessage(
  op: Option[OpType],
)

case class ConnectionMessage(
  a: Option[Int],
  b: Option[Int],
) extends ResponseMessage

case class StatusMessage(
  c: Option[Int],
  d: Option[Int],
) extends ResponseMessage

type OpTypes = OpTypes.Value
object OpTypes extends Enumeration {
  val Connection = Value("connection")
  val Status = Value("status")

How can I write custom JsonFormat instances so that depending on the value of op I create the correct type? So that it can be used as such:

> jsValue.convertTo[ResponseMessage] And the outvalue will be either
> ConnectionMessage or StatusMessage?

注意:扩展 case class 即 ResponseMessage 不是最佳做法。 Google "case class inheritance"...

关于你关于 JsonFormat 的问题,我会为每个子 class 定义特定的 JsonFormat,然后根据类似的那些为 ResponseMessage 定义一个:

import spray.json._

abstract class ResponseMessage(val op: Option[OpTypes])
object ResponseMessage {
  implicit object jsonFormat extends JsonFormat[ResponseMessage] {
    override def read(json: JsValue): ResponseMessage = json match {
      case JsObject(fields) =>
        fields.get("op") match {
          case Some(JsString("connection")) => json.convertTo[ConnectionMessage]
          case Some(JsString("status")) => json.convertTo[StatusMessage]
          case op => // unknown op
        }
      case _ => // invalid json
    }

    override def write(obj: ResponseMessage): JsValue = obj match {
      case connection: ConnectionMessage => connection.toJson
      case status: StatusMessage => status.toJson
    }
  }
}

case class ConnectionMessage(
                              a: Option[Int],
                              b: Option[Int]
                            ) extends ResponseMessage(Some(OpTypes.Connection))
object ConnectionMessage {
  implicit object jsonFormat extends JsonFormat[ConnectionMessage] {
    override def read(json: JsValue): ConnectionMessage =
      // json -> ConnectionMessage

    override def write(obj: ConnectionMessage): JsValue =
      // ConnectionMessage -> json
  }
}

case class StatusMessage(
                          c: Option[Int],
                          d: Option[Int]
                        ) extends ResponseMessage(Some(OpTypes.Status))
object StatusMessage {
  implicit object jsonFormat extends JsonFormat[StatusMessage] {
    override def read(json: JsValue): StatusMessage =
      // json -> StatusMessage

    override def write(obj: StatusMessage): JsValue =
      // StatusMessage -> json
  }
}

type OpTypes = OpTypes.Value

object OpTypes extends Enumeration {
  val Connection = Value("connection")
  val Status = Value("status")
}