Search code examples
scalaspray-json

How to represent optional fields in spray-json?


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:

{"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.


Solution

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