我正在使用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:具有Serializable的产品中出现类型不匹配。必需:org.json4s.package.JValue”。
有趣的是render(("fld2" -> "sometimes") ~ fld1)
有效,render(fld1)
也有效。问题似乎与json
推断的类型有关。
我该如何解决这个问题?
答案 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
子句的输入为JObject
,else
子句为(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))