提问一个用 Java 解析 JSON 的方法

326 天前
 thebeacon

业务需要按照”response. customerInfo.children“来获取到每个 children 节点 list 并需要包含该节点的所有父节点及其属性(理论上好像只要在解析的时候将父节点传进来即可,因为子节点确定了那他的父节点肯定也是确定的,不存在 list 的问题),想了半天没有想出来,请各位大佬支支招!

原 json:

{
    "response": {
        "customerInfo": [
            {
                "uuid": "59a49249342f4262bd59ea2e36ac40d3",
                "name": "张三",
                "phoneNo": "15566669999",
                "idCard": "123456789965412544545",
                "wife": {
                    "uuid": "51e211b7d1e54578b0093a5418868aa6",
                    "name": "李四",
                    "phoneNo": "15566668888",
                    "idCard": "1236547896513245"
                },
                "children": [
                    {
                        "uuid": "8e1b40a3bc4a4f709a7076002132c7e3",
                        "name": "张五",
                        "phoneNo": "15523645896",
                        "idCard": "523641528965425"
                    },
                    {
                        "uuid": "cd73bd47b6a945e0b3ca86927a154c1b",
                        "name": "张六",
                        "phoneNo": "15562458952",
                        "idCard": "652154258962541"
                    }
                ]
            },
            {
                "uuid": "c752f9ff5a0d4776880e8ea1f0fcc482",
                "name": "王五",
                "phoneNo": "13652366548",
                "idCard": "123654856525665"
            }
        ]
    }
}

解析后需要得到的 list

[
    {
        "response": {
            "customerInfo": {
                "uuid": "59a49249342f4262bd59ea2e36ac40d3",
                "name": "张三",
                "phoneNo": "15566669999",
                "idCard": "123456789965412544545",
                "wife": {
                    "uuid": "51e211b7d1e54578b0093a5418868aa6",
                    "name": "李四",
                    "phoneNo": "15566668888",
                    "idCard": "1236547896513245"
                },
                "children": {
                    "uuid": "8e1b40a3bc4a4f709a7076002132c7e3",
                    "name": "张五",
                    "phoneNo": "15523645896",
                    "idCard": "523641528965425"
                }
            }
        }
    },
    {
        "response": {
            "customerInfo": {
                "uuid": "59a49249342f4262bd59ea2e36ac40d3",
                "name": "张三",
                "phoneNo": "15566669999",
                "idCard": "123456789965412544545",
                "wife": {
                    "uuid": "51e211b7d1e54578b0093a5418868aa6",
                    "name": "李四",
                    "phoneNo": "15566668888",
                    "idCard": "1236547896513245"
                },
                "children": {
                    "uuid": "cd73bd47b6a945e0b3ca86927a154c1b",
                    "name": "张六",
                    "phoneNo": "15562458952",
                    "idCard": "652154258962541"
                }
            }
        }
    }
]

就相当于是把每个子节点单独拿出来和他的各级父节点组成一个 JsonObject ,大佬们有没有什么妙招哇

1993 次点击
所在节点    Java
19 条回复
blankmiss
326 天前
转成对象然后操作
thebeacon
326 天前
@blankmiss 如果是固定格式的可以这样做,关键就是这个 json 是不固定的,需要通用化编码
lyxeno
326 天前
你就正常创建一个 CustomerInfo 实体类拿 jackson 去反序列化生成出实体类后,
再根据你需要得到的形态去构建对象,然后 jackson 序列化为 json 就好了

```java
@Data
class CustomerInfo{
String uuid;
String name;
/* 其他属性 */
List<CustomerInfo> children;
CustomerInfo wife;
}
```
lyxeno
326 天前
实在不行反序列化成 Map 去做处理也可以的。就是丑陋了点
darkengine
326 天前
格式不固定也得有规律吧,用个 type 之类的参数代表不行么
thebeacon
326 天前
@darkengine 产品就是要整一个无敌通用,什么 json 进来我们都要根据一个 key 来拆分出多个子节点列表(包含所有唯一父节点内容)
thebeacon
326 天前
@lyxeno #4 感谢回复,实际上这个 json 不是特定格式的,没办法硬编码
YepTen
326 天前
用 JSON 的 tree model 试试
thinkershare
326 天前
@thebeacon 各个 json 库不是都有自己的未解析的 Json Object 吗?按照 JSON 可能的格式逐个扫描吧。再不行你自己写个 json 序列&反序列化器好了,反正也不是什么难事,这样性能反正也不会好到哪里去,所以完全不需要考虑 JSON 库的性能优化。
6IbA2bj5ip3tK49j
326 天前
循环 jsonnode 的节点,然后根据是不是 array 做判断处理,递归下去即可。
你需要确定你的规则。
比如,父节点的兄弟节点也是数组,期望得到什么样的结果?

{
"keyA": [
{
"name": "M"
},
{
"name": "N"
}
],
"keyB": [
{
"name": "O"
},
{
"name": "P"
}
]
}
gogo789
326 天前
这个 json 有点混乱了。首先会有一个 customerInfoDTO.java 里面包含 uuid,name,phoneNo...字段和 wife.java,children.java 两个对象。你直接通过 JSONObject.parseObject(jsonStr,customerInfoDTO.class) 除了 children 都可以解析到,关于 children 就只能自己手动处理了。可以通过 jsonObject.getJSONObject("response").getJSONArray("customerInfo").getJSONObject(0).getJSONArray("children") 获取到一个 children 的 jsonArray ,然后手动遍历解析这个 Array ,复制上面的解析结果往里面填充 children
Dlin
326 天前
可以先转为 ObjectNode,再根据属性来重新构建新的 ObjectNode
xinxingi
326 天前
@thebeacon 考虑到你的 json 格式不固定,那就简单粗暴一点。拿到原 json 后,把原 json 的 response. customerInfo.children 全部拿出来装入集合。清空原 json 中的 response. customerInfo.children.拿刚才的集合一个一个的全部遍历填充进去。结束
bill110100
326 天前
@thebeacon 那你只能和产品怼,要不改需求,要不给开放时间,或者干脆要求换语言框架,理由很明确,java 强类型语言,不可能做到灵活多变的参数系统,
还有,如果数据类型可以有某些特殊的字段,或者可以给你传输一些可以辨别格式的字段的话,可以通过多态的形式来转换,jackson 有做多态转换的注解,根据传输的参数是否有某字段为判断条件,将 json 反序列化为某一个父类下的不同子类。
@JsonTypeInfo @JsonSubTypes 这几个注解可以看一下。
JinTianYi456
326 天前
JSON.parseObject("")
.getJSONObject("response")
.getJSONArray("customerInfo")
.stream()
.map(t -> Collections.singletonMap("response", Collections.singletonMap("customerInfo", t)))
.collect(Collectors.toList());

这样?
Corolin
326 天前
好像 JsonPath 可以 反过来一层层去取?$.response.customerInfo[*]
https://jsonpath.com/
c3de3f21
326 天前
得需要个 type 字段。。。
c3de3f21
326 天前
或者说需要一些 描述 json 本身的字段才行。
mmdsun
325 天前
转对象处理,动态的用在对象里面用 map 声明 @JsonAnyGetter 、 @JsonAnySetter 即可。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/964087

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX