Как представить необязательные поля в spray-json?

У меня есть необязательное поле в моих запросах:

case class SearchRequest(url: String, nextAt: Option[Date])

Мой протокол:

object SearchRequestJsonProtocol extends DefaultJsonProtocol {
    implicit val searchRequestFormat = jsonFormat(SearchRequest, "url", "nextAt")
}

Как сделать поле nextAt необязательным, чтобы следующие объекты JSON правильно читались и принимались:

{"url":"..."}
{"url":"...", "nextAt":null}
{"url":"...", "nextAt":"2012-05-30T15:23Z"}

На самом деле меня не волнует нулевой регистр, но если у вас есть подробности, было бы неплохо. Я использую спрей-json, и у меня сложилось впечатление, что использование Option пропустит поле, если оно отсутствовало в исходном объекте JSON.


person François Beausoleil    schedule 30.05.2012    source источник


Ответы (6)


Возможно, вам придется создать явный формат (предупреждение: псевдокодиш):

object SearchRequestJsonProtocol extends DefaultJsonProtocol {
    implicit object SearchRequestJsonFormat extends JsonFormat[SearchRequest] {
        def read(value: JsValue) = value match {
            case JsObject(List(
                    JsField("url", JsString(url)),
                    JsField("nextAt", JsString(nextAt)))) =>
                SearchRequest(url, Some(new Instant(nextAt)))

            case JsObject(List(JsField("url", JsString(url)))) =>
                SearchRequest(url, None)

            case _ =>
                throw new DeserializationException("SearchRequest expected")
        }

        def write(obj: SearchRequest) = obj.nextAt match {
            case Some(nextAt) => 
                JsObject(JsField("url", JsString(obj.url)),
                         JsField("nextAt", JsString(nextAt.toString)))
            case None => JsObject(JsField("url", JsString(obj.url)))
        }
    }
}
person James Marble    schedule 30.05.2012

У меня работает (spray-json 1.1.1 scala 2.9.1 build)

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

// string instead of date for simplicity
case class SearchRequest(url: String, nextAt: Option[String])

// btw, you could use jsonFormat2 method here
implicit val searchRequestFormat = jsonFormat(SearchRequest, "url", "nextAt")

assert {
  List(
    """{"url":"..."}""",
    """{"url":"...", "nextAt":null}""",
    """{"url":"...", "nextAt":"2012-05-30T15:23Z"}""")
  .map(_.asJson.convertTo[SearchRequest]) == List(
    SearchRequest("...", None),
    SearchRequest("...", None),
    SearchRequest("...", Some("2012-05-30T15:23Z")))
}
person elbowich    schedule 30.05.2012
comment
А, я использую spray-json 1.0.0, Scala 2.9.0.1. Я хочу обновиться в ближайшее время, но я не там. все же. Спасибо за Ваш ответ! - person François Beausoleil; 31.05.2012

Используйте черту NullOptions, чтобы отключить пропуск nulls: https://github.com/spray/spray-json#nulloptions Пример: https://github.com/spray/spray-json/blob/master/src/test/scala/spray/json/ProductFormatsSpec.scala

person Alex Abdugafarov    schedule 22.04.2014

Не знаю, поможет ли это вам, но вы можете присвоить этому полю значение по умолчанию в определении класса case, поэтому, если поле не находится в json, оно присвоит ему значение по умолчанию.

person Mohammad Qandeel    schedule 23.04.2014
comment
У меня это не сработало... нужно что-то настраивать? - person samthebest; 30.11.2014

Легко.

import cc.spray.json._
trait MyJsonProtocol extends DefaultJsonProtocol {
  implicit val searchFormat = new JsonWriter[SearchRequest] {
    def write(r: SearchRequest): JsValue = {
      JsObject(
        "url" -> JsString(r.url),
        "next_at" -> r.nextAt.toJson,
      )
    }
  }
}

class JsonTest extends FunSuite with MyJsonProtocol {
test("JSON") {
    val search = new SearchRequest("www.site.ru", None)
    val marshalled = search.toJson
    println(marshalled)
  }
}
person Dmitry Kaltovich    schedule 08.06.2018

Для всех, кто наткнулся на этот пост и хочет обновить ответ Франсуа Босолея для более новых версий Spray (около 2015+?), JsField устарел как общедоступный член JsValue; вы должны просто предоставить список кортежей вместо JsFields. Однако их ответ точен.

person smohan123    schedule 22.02.2019