Spray-json DefaultJsonProtocol со значением по умолчанию

Я видел несколько постов по этому вопросу, но я не нашел никакого решения, чтобы избежать передачи значения по умолчанию. У меня есть следующий код:

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

Я хотел бы выполнить маршал и демаршал во время обработки httprequest для того же. Я следовал подходу, описанному на нескольких форумах:

Я изменил свои классы case, чтобы добавить тип вида следующим образом:

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 ответ

Решение

Я бы определил обычай JsonFormat[Message] экземпляр с автоматически сгенерированными форматами для каждого типа сообщений. При методе записи я сопоставляю шаблоны и пишу json с автоматически сгенерированными форматами, а при методе чтения я пытаюсь разобрать 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()}"))

  }
Другие вопросы по тегам