如果缺少可选值

时间:2015-12-16 16:31:41

标签: json scala playframework

使用Play的JSON API(play.api.libs.json)来考虑此示例:

case class FooJson(
   // lots of other fields omitted
   location: Option[LocationJson]
)

object FooJson {
  implicit val writes = Json.writes[FooJson]
}

case class LocationJson(latitude: Double, longitude: Double)

object LocationJson {
  implicit val writes = Json.writes[LocationJson]
}

如果locationNone,则生成的JSON根本不会有location字段。这很好,而且不够深入。但是,如果我出于某种原因(例如,为了让我的API更加自我记录),如何在JSON中明确输出null

{      
  "location": null
}

我还尝试将字段定义为location: LocationJson并将option.orNull传递给它,但它不起作用(scala.MatchError: null位于play.api.libs.json.OWrites$$anon$2.writes)。对于非自定义类型(如String或Double),此方法在JSON输出中生成null。

所以,使用Json.writes[FooJson] ,如上所示(或者同样简单的东西,即必须编写自定义Writes实现),是否有一种在JSON中包含空值的简洁方法?

我所问的与杰克逊图书馆中的JsonInclude.Include.ALWAYS类似(也是杰克逊的默认行为)。同样in Gson这将是微不足道的  (new GsonBuilder().serializeNulls().create())。

播放2.4.4

4 个答案:

答案 0 :(得分:4)

Greg Methvin,一位Play提交者,wrote this answer给我一个相关的GitHub问题:

  

JSON宏只支持一种编码可选值的方法,   这是从JSON中省略None值。这不是一个bug但是   而是对实施的限制。如果你想包括   遗憾的是,您不得不实施自己的Writes

     

我认为我们应该尝试为此提供更多可配置性   宏虽然。

在这种情况下,我会让Play在值为null时排除此字段,即使它稍微牺牲了API一致性和自我可记录性。它仍然是一个小问题(在这个特定的API中),它不保证代码的泛滥,就像自定义Writes对具有十几个值的案例类所需要的那样。

我希望他们在未来的Play版本中确实可以配置它。

答案 1 :(得分:0)

这是一种方法:

object MyWrites extends DefaultWrites{

  override def OptionWrites[T](implicit fmt: Writes[T]): Writes[Option[T]] = new Writes[Option[T]] {
    override def writes(o: Option[T]): JsValue = {
      o match {
        case Some(a) => Json.toJson(a)(fmt)
        case None => JsNull
      }
    }
  }
}

这将覆盖不会创建元素的默认实现。我在你的示例代码中使用了这个:

case class FooJson(
                // ...
                location: Option[LocationJson]
              )

case class LocationJson(latitude: Double, longitude: Double)

object LocationJson {
  implicit val writes = Json.writes[LocationJson]
}

implicit val fooJsonWriter: Writes[FooJson] = new Writes[FooJson] {
  override def writes(o: FooJson): JsValue = {
    JsObject(Seq(
      "location" -> Json.toJson(o.location)
      // Additional fields go here.
    ))
  }
}

Json.toJson(FooJson(None))

得到了这个结果res0: play.api.libs.json.JsValue = {"location":null}

答案 2 :(得分:0)

如果我们具有空值,则必须在case类中添加带有成员的选项,以解决问题

case class response(
 name:String,
 age: option[int]
)

 object response {
    implicit val format = Json.format[response]
  }

这是我们的答案。并且如果我们是年龄的JSON响应将为null,这将为我们解决问题。

答案 3 :(得分:0)

你好,将来。

从Play 2.7开始,针对自动JSON编解码器引入了一个相当简单的解决方案。我们可以在select t1.*, t2.cost from table1 t1 inner join table2 t2 on t2.duration between cast(substring(duration, 1, instr(duration, '-') - 1) as int) and cast(substring(duration, instr(duration, '-') + 1) as int) / JsonConfiguration / Format的范围内为Reads引入适当的隐式值。以下配置将为空的Writes写入null,而不是完全忽略这些字段。

Option

Reference