如何使用JSON4S有条件地生成JSON

时间:2013-01-25 12:03:23

标签: json scala lift-json

我正在使用JSON4S生成一些JSON。

如果符合条件,我想提供以下内容:

{"fld1":"always", "fld2":"sometimes"}

如果不符合条件,我想制作:

{"fld1":"always"}

到目前为止我尝试的是:

val fld1 = "fld1" -> "always"

val json = if(condition) ("fld2" -> "sometimes") ~ fld1 else fld1

compact(render(json))

但是,这使我在render“Found:具有Seri​​alizable的产品中出现类型不匹配。必需:org.json4s.package.JValue”。

有趣的是render(("fld2" -> "sometimes") ~ fld1)有效,render(fld1)也有效。问题似乎与json推断的类型有关。

我该如何解决这个问题?

3 个答案:

答案 0 :(得分:4)

虽然目前的两个答案都给出了合适的解决方法,但两者都没有解释这里发生了什么。问题是,如果我们有两种类型,如:

trait Foo
trait Bar

从一个到另一个的隐式转换(或视图):

implicit def foo2bar(foo: Foo): Bar = new Bar {}

Foo子句的then条件及其Bar子句的else条件仍将被键入为Foo的最小上限和Bar(在这种情况下为Object,在您的情况下为Product with Serializable)。

这是因为类型推断系统不会介入并说,我们可以将Foo视为Bar,所以我只需将整个事物键入Bar

如果您考虑它,这是有道理的 - 例如,如果它愿意处理这样的条件,如果我们双向进行隐式转换会怎么做?

在您的情况下,then子句的输入为JObjectelse子句为(String, String)。我们有一个从后者到前者的视图,但除非您通过明确声明类型或使用以下内容表明您希望整个事件以JObject结尾,否则不会在此处使用它。表达式必须是JObject的上下文。

考虑到所有这些,最简单的解决方法可能只是通过为fld1提供类似这样的类型注释来确保从一开始就适当地键入两个子句:

val fld1: JObject = "fld1" -> "always"

现在您的条件将按原样适当地键入,不带类型注释。

答案 1 :(得分:2)

这不是我能想到的最好的方式,但是自己声明类型应该有效:

val json: JObject = 
  if(condition) ("fld2" -> "sometimes") ~ fld1 else fld1

compact(render(json))

另外,请注意您可以通过类型推断来帮助自己:如果您可以一次性渲染:

compact(render(
  if(condition) fld1 ~ ("fld2" -> "sometimes") else fld1  
))

答案 2 :(得分:2)

另一种方法是将条件值设置为选项。

val json = fld1 ~ ("fld2" -> (if (condition) Some("sometimes") else None))

compact(render(json))