【发布时间】:2013-11-30 12:26:49
【问题描述】:
在 Play Framework 的主页上,他们声称“JSON 是一等公民”。我还没有看到证明。
在我的项目中,我正在处理一些非常复杂的 JSON 结构。这只是一个非常简单的例子:
{
"key1": {
"subkey1": {
"k1": "value1"
"k2": [
"val1",
"val2"
"val3"
]
}
}
"key2": [
{
"j1": "v1",
"j2": "v2"
},
{
"j1": "x1",
"j2": "x2"
}
]
}
现在我了解到 Play 正在使用 Jackson 来解析 JSON。我在我的 Java 项目中使用 Jackson,我会做一些简单的事情:
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> obj = mapper.readValue(jsonString, Map.class);
这可以很好地将我的 JSON 解析为我想要的 Map 对象 - 字符串和对象对的映射,并且可以让我轻松地将数组转换为 ArrayList。
Scala/Play 中的相同示例如下所示:
val obj: JsValue = Json.parse(jsonString)
这反而给了我一个专有的JsObjecttype,这并不是我真正想要的。
我的问题是:我能否像在 Java 中那样轻松地将 Scala/Play 中的 JSON 字符串解析为 Map 而不是 JsObject?
附带问题:在 Scala/Play 中使用 JsObject 代替 Map 是否有原因?
我的堆栈:Play Framework 2.2.1 / Scala 2.10.3 / Java 8 64bit / Ubuntu 13.10 64bit
更新:我可以看到 Travis 的回答得到了赞成,所以我想这对每个人来说都有意义,但我仍然看不到如何应用它来解决我的问题。假设我们有这个例子(jsonString):
[
{
"key1": "v1",
"key2": "v2"
},
{
"key1": "x1",
"key2": "x2"
}
]
好吧,根据所有指示,我现在应该放入所有我不明白其目的的样板:
case class MyJson(key1: String, key2: String)
implicit val MyJsonReads = Json.reads[MyJson]
val result = Json.parse(jsonString).as[List[MyJson]]
看起来不错,对吧?但是等一下,数组中有另一个元素完全破坏了这种方法:
[
{
"key1": "v1",
"key2": "v2"
},
{
"key1": "x1",
"key2": "x2"
},
{
"key1": "y1",
"key2": {
"subkey1": "subval1",
"subkey2": "subval2"
}
}
]
第三个元素不再与我定义的案例类匹配——我又回到了第一格。我每天都可以在 Java 中使用这种更复杂的 JSON 结构,Scala 是否建议我应该简化我的 JSON 以适应它的“类型安全”策略?如果我错了,请纠正我,但我认为该语言应该为数据服务,而不是相反?
UPDATE2: 解决方案是使用 Jackson 模块进行 scala(我的回答中的示例)。
【问题讨论】:
-
@m09:我实际上认为这是一个非常合理的问题。基于类型类的解码 方法与您在 Jackson 之类的库中找到的方法非常不同(我认为更好,正如我在下面试图论证的那样)。
-
@TravisBrown:看到这个问题并且没有提到读取和 JSON 路径,我只是担心 OP 在要求之前没有花时间实际尝试获得 Play 的做事方式他过去工作流程的精确副本。我确实同意这两种方法是非常不同的,我认为这并不是说 play 的方法更好,而是一个事实;)
-
@m09 这是因为我阅读了我提出这个问题的文档(playframework.com/documentation/2.2.1/ScalaJson)。在我看来,有很多额外的努力和专有方法只是为了使其“类型安全”或任何目标。
-
@Caballero:就我个人而言,我不认为这是“额外的努力”——它更像是将努力提前,以便编译器可以帮助您。当然口味不同,但我偶尔会被
Map[String, Object]-plagued 库困住,我觉得此时的体验非常糟糕。
标签: java json scala playframework playframework-2.0