Scala/Play:将 JSON 解析为 Map 而不是 JsObject [英] Scala/Play: parse JSON into Map instead of JsObject

查看:31
本文介绍了Scala/Play:将 JSON 解析为 Map 而不是 JsObject的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 Play Framework 的主页上,他们声称JSON 是一等公民".我还没有看到证据.

在我的项目中,我正在处理一些非常复杂的 JSON 结构.这只是一个非常简单的例子:

<代码>{key1":{子键1":{k1":值1"k2":["val1",val2"val3"]}}key2":[{"j1": "v1",j2":v2"},{"j1": "x1",j2":x2"}]}

现在我知道 Play 正在使用 Jackson 来解析 JSON.我在我的 Java 项目中使用 Jackson,我会做一些简单的事情:

ObjectMapper mapper = new ObjectMapper();映射<字符串,对象>obj = mapper.readValue(jsonString, Map.class);

这可以很好地将我的 JSON 解析为我想要的 Map 对象 - 字符串和对象对的映射,并且可以让我轻松地将数组转换为 ArrayList.

Scala/Play 中的相同示例如下所示:

val obj: JsValue = Json.parse(jsonString)

这反而给了我一个专有的 JsObject type我在追求什么.

我的问题是:我能否像在 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)隐式 val MyJsonReads = Json.reads[MyJson]val 结果 = 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(我的回答中的示例).

解决方案

我选择使用 Scala 的杰克逊模块.

import com.fasterxml.jackson.databind.ObjectMapper导入 com.fasterxml.jackson.module.scala.DefaultScalaModule导入 com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapperval mapper = new ObjectMapper() 与 ScalaObjectMappermapper.registerModule(DefaultScalaModule)val obj = mapper.readValue[Map[String, Object]](jsonString)

On Play Framework's homepage they claim that "JSON is a first class citizen". I have yet to see the proof of that.

In my project I'm dealing with some pretty complex JSON structures. This is just a very simple example:

{
    "key1": {
        "subkey1": {
            "k1": "value1"
            "k2": [
                "val1",
                "val2"
                "val3"
            ]
        }
    }
    "key2": [
        {
            "j1": "v1",
            "j2": "v2"
        },
        {
            "j1": "x1",
            "j2": "x2"
        }
    ]
}

Now I understand that Play is using Jackson for parsing JSON. I use Jackson in my Java projects and I would do something simple like this:

ObjectMapper mapper = new ObjectMapper();
Map<String, Object> obj = mapper.readValue(jsonString, Map.class);

This would nicely parse my JSON into Map object which is what I want - Map of string and object pairs and would allow me easily to cast array to ArrayList.

The same example in Scala/Play would look like this:

val obj: JsValue = Json.parse(jsonString)

This instead gives me a proprietary JsObject type which is not really what I'm after.

My question is: can I parse JSON string in Scala/Play to Map instead of JsObject just as easily as I would do it in Java?

Side question: is there a reason why JsObject is used instead of Map in Scala/Play?

My stack: Play Framework 2.2.1 / Scala 2.10.3 / Java 8 64bit / Ubuntu 13.10 64bit

UPDATE: I can see that Travis' answer is upvoted, so I guess it makes sense to everybody, but I still fail to see how that can be applied to solve my problem. Say we have this example (jsonString):

[
    {
        "key1": "v1",
        "key2": "v2"
    },
    {
        "key1": "x1",
        "key2": "x2"
    }
]

Well, according to all the directions, I now should put in all that boilerplate that I otherwise don't understand the purpose of:

case class MyJson(key1: String, key2: String)
implicit val MyJsonReads = Json.reads[MyJson]
val result = Json.parse(jsonString).as[List[MyJson]]

Looks good to go, huh? But wait a minute, there comes another element into the array which totally ruins this approach:

[
    {
        "key1": "v1",
        "key2": "v2"
    },
    {
        "key1": "x1",
        "key2": "x2"
    },
    {
        "key1": "y1",
        "key2": {
            "subkey1": "subval1",
            "subkey2": "subval2"
        }
    }
]

The third element no longer matches my defined case class - I'm at square one again. I am able to use such and much more complicated JSON structures in Java everyday, does Scala suggest that I should simplify my JSONs in order to fit it's "type safe" policy? Correct me if I'm wrong, but I though that language should serve the data, not the other way around?

UPDATE2: Solution is to use Jackson module for scala (example in my answer).

解决方案

I've chosen to use Jackson module for scala.

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper

val mapper = new ObjectMapper() with ScalaObjectMapper
mapper.registerModule(DefaultScalaModule)
val obj = mapper.readValue[Map[String, Object]](jsonString)

这篇关于Scala/Play:将 JSON 解析为 Map 而不是 JsObject的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆