Spray-json DefaultJsonProtocol具有默认值

时间:2016-04-06 21:34:20

标签: akka spray-json

我在这个问题上看过多篇文章,但我找不到任何避免传递默认值的解决方案。我有以下代码:

trait Message
case class StringMessag(msg:String) extends Message
case class PersonalMessage(msg:String, from:String, to:String) extends Message

我想在httprequest处理过程中编组和解组。我遵循多个论坛中描述的方法:

我修改了我的case类以添加kind类型,如下所示:

case class StringMessag(msg:String, val kind:String="String") extends Message

case class PersonalMessage(msg:String, from:String, to:String, val kind:String="Personal") extends Message

implicit val stringMessageFormat = jsonFormat2(StringMessage.apply)  
implicit val personalMessageFormat = jsonFormat4(PersonalMessage.apply)  

implicit object MyJsonFormat extends RootJsonFormat[Message] {
  def write(a: Message) = a match {
    case a: StringMessage => a.toJson
    case b: PersonalMessage => b.toJson

  }
  def read(value: JsValue) = 
    value.asJsObject.fields("kind") match {
      case JsString("String") => value.convertTo[StringMessage]
      case JsString("Personal") => value.convertTo[PersonalMessage]

    }
}

这很好用,但客户端程序必须为“kind”发送额外的默认值,即使kind在case类中定义了默认值。我们不能避免客户端传递的额外值,以便RouteDSL可以解组而不会出现任何错误吗?

我尝试了以下解决方案;哪个有效,但看起来会更干净。

case class StringMessag(msg:String) extends Message

case class PersonalMessage(msg:String, from:String, to:String) extends Message


implicit val stringMessageFormat = jsonFormat1(StringMessage.apply)  
implicit val personalMessageFormat = jsonFormat3(PersonalMessage.apply) 
def read(value: JsValue) = 
    value match {
      case obj:JsObject if(obj.fields.size==1 && obj.fields.contains("msg")) => value.convertTo[StringMessage]
      case obj:JsObject if(obj.fields.size==3 && obj.fields.contains("from")) => value.convertTo[PersonalMessage]

    }

由于 阿伦

1 个答案:

答案 0 :(得分:1)

我会为每种消息类型定义一个自定义JsonFormat[Message]实例,其中包含自动生成的格式。在write方法上,我会模式匹配并用自动生成的格式写json,在read方法上,我会尝试逐个解析带有自动生成格式的json并返回第一个成功的结果。

以下是一个示例实现

implicit object MessageFormat extends JsonFormat[Message] {

    val stringMessageFormat = jsonFormat1(StringMessage)
    val personalMessageFormat = jsonFormat3(PersonalMessage)

    def write(obj: Message): JsValue = obj match {
      case x: StringMessage => x.toJson
      case x: PersonalMessage => x.toJson
    }

    def read(json: JsValue): Message =
      Try(personalMessageFormat.read(json))
        .orElse(Try(stringMessageFormat.read(json)))
        .getOrElse(deserializationError(s"Invalid message format: ${json.toString()}"))

  }