17

我的请求中有一个可选字段:

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"}

我实际上并不真正关心 null 案例,但是如果您有详细信息,那就太好了。我正在使用 spray-json,并且认为如果原始 JSON 对象上不存在该字段,则使用 Option 会跳过该字段。

4

6 回答 6

28

为我工作(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")))
}
于 2012-05-30T18:06:36.367 回答
11

您可能必须创建一个明确的格式(警告:psuedocodish):

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)))
        }
    }
}
于 2012-05-30T16:22:52.780 回答
6

使用NullOptionstrait 禁用跳过nulls: https ://github.com/spray/spray-json#nulloptions 示例: https ://github.com/spray/spray-json/blob/master/src/test/scala/spray/ json/ProductFormatsSpec.scala

于 2014-04-22T15:44:32.540 回答
0

不知道这是否对您有帮助,但您可以在案例类定义中为该字段指定默认值,因此如果该字段不在 json 中,它将为其分配默认值。

于 2014-04-23T11:30:50.190 回答
0

简单的。

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)
  }
}
于 2018-06-08T08:07:45.827 回答
0

对于碰巧看到这篇文章并希望更新 François Beausoleil 对新版本 Spray(大约 2015 年+?)的答案的任何人,JsField 已被弃用为 JsValue 的公共成员;你应该简单地提供一个元组列表而不是 JsFields。不过,他们的答案是准确的。

于 2019-02-22T22:39:56.547 回答