2

我正在使用 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“找到:具有可序列化的产品。必需:org.json4s.package.JValue”中的类型不匹配。

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

我该如何解决这个问题?

4

3 回答 3

4

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

trait Foo
trait Bar

以及从一个到另一个的隐式转换(或view ):

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

带有Foofor itsthen子句和 a Barfor its子句的条件仍将被键入为andelse的最小上限(在这种情况下,在您的情况下)。FooBarObjectProduct with Serializable

这是因为类型推断系统不会介入并说,好吧,我们可以将其Foo视为 a Bar,所以我只需将整个内容输入为 a Bar

如果您考虑一下,这是有道理的——例如,如果它愿意处理这样的条件,那么如果我们有两种方式的隐式转换,它会做什么?

在您的情况下,then子句的类型为 a JObjectelse子句为 a (String, String)。我们有从后者到前者的观点,但是除非您JObject通过显式声明类型或通过在它必须是一个JObject.

考虑到所有这些,最简单的解决方法可能就是确保从一开始就正确键入两个子句,方法是提供如下类型注释fld1

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

现在,您的条件将按原样正确键入,而无需类型注释。

于 2013-01-25T13:35:31.693 回答
2

不是我能想到的最好的方式,但自己声明类型应该可以工作:

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

compact(render(json))

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

compact(render(
  if(condition) fld1 ~ ("fld2" -> "sometimes") else fld1  
))
于 2013-01-25T12:14:25.843 回答
2

另一种方法是将条件值装箱到选项中。

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

compact(render(json))
于 2013-01-25T12:42:42.067 回答