scala 如何在spray-json中表示可选字段?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10819344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:11:56  来源:igfitidea点击:

How to represent optional fields in spray-json?

scalaspray-json

提问by Fran?ois Beausoleil

I have an optional field on my requests:

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

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

My protocol is:

我的协议是:

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

How do I mark the nextAt field optional, such that the following JSON objects will be correctly read and accepted:

如何将 nextAt 字段标记为可选,以便正确读取和接受以下 JSON 对象:

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

I actually don't really care about the null case, but if you have details, it would be nice. I'm using spray-json, and was under the impression that using an Option would skip the field if it was absent on the original JSON object.

我实际上并不关心 null 情况,但是如果您有详细信息,那就太好了。我正在使用 Spray-json,并且我的印象是,如果原始 JSON 对象中不存在该字段,则使用 Option 会跳过该字段。

采纳答案by James Marble

You might have to create an explicit format (warning: 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)))
        }
    }
}

回答by elbowich

Works for me (spray-json 1.1.1 scala 2.9.1 build)

对我有用(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")))
}

回答by Mohammad Qandeel

Don't know if this will help you but you can give that field a default value in the case class definition, so if the field is not in the json, it will assign the default value to it.

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

回答by Dmitry Kaltovich

Easy.

简单。

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

回答by smohan123

For anyone who is chancing upon this post and wants an update to Fran?ois Beausoleil's answer for newer versions of Spray (circa 2015+?), JsField is deprecated as a public member of JsValue; you should simply supply a list of tuples instead of JsFields. Their answer is spot-on, though.

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