V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
thebeacon
V2EX  ›  Java

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

  •  
  •   thebeacon · 2023-08-10 13:58:23 +08:00 · 2153 次点击
    这是一个创建于 473 天前的主题,其中的信息可能已经有所发展或是发生改变。

    业务需要按照”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 ,大佬们有没有什么妙招哇

    19 条回复    2023-08-11 12:52:34 +08:00
    blankmiss
        1
    blankmiss  
       2023-08-10 14:04:34 +08:00
    转成对象然后操作
    thebeacon
        2
    thebeacon  
    OP
       2023-08-10 14:06:41 +08:00
    @blankmiss 如果是固定格式的可以这样做,关键就是这个 json 是不固定的,需要通用化编码
    lyxeno
        3
    lyxeno  
       2023-08-10 14:08:57 +08:00
    你就正常创建一个 CustomerInfo 实体类拿 jackson 去反序列化生成出实体类后,
    再根据你需要得到的形态去构建对象,然后 jackson 序列化为 json 就好了

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

    {
    "keyA": [
    {
    "name": "M"
    },
    {
    "name": "N"
    }
    ],
    "keyB": [
    {
    "name": "O"
    },
    {
    "name": "P"
    }
    ]
    }
    gogo789
        11
    gogo789  
       2023-08-10 15:59:01 +08:00
    这个 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
        12
    Dlin  
       2023-08-10 16:04:33 +08:00
    可以先转为 ObjectNode,再根据属性来重新构建新的 ObjectNode
    xinxingi
        13
    xinxingi  
       2023-08-10 16:45:49 +08:00
    @thebeacon 考虑到你的 json 格式不固定,那就简单粗暴一点。拿到原 json 后,把原 json 的 response. customerInfo.children 全部拿出来装入集合。清空原 json 中的 response. customerInfo.children.拿刚才的集合一个一个的全部遍历填充进去。结束
    bill110100
        14
    bill110100  
       2023-08-10 17:01:12 +08:00
    @thebeacon 那你只能和产品怼,要不改需求,要不给开放时间,或者干脆要求换语言框架,理由很明确,java 强类型语言,不可能做到灵活多变的参数系统,
    还有,如果数据类型可以有某些特殊的字段,或者可以给你传输一些可以辨别格式的字段的话,可以通过多态的形式来转换,jackson 有做多态转换的注解,根据传输的参数是否有某字段为判断条件,将 json 反序列化为某一个父类下的不同子类。
    @JsonTypeInfo @JsonSubTypes 这几个注解可以看一下。
    JinTianYi456
        15
    JinTianYi456  
       2023-08-10 17:37:58 +08:00
    JSON.parseObject("")
    .getJSONObject("response")
    .getJSONArray("customerInfo")
    .stream()
    .map(t -> Collections.singletonMap("response", Collections.singletonMap("customerInfo", t)))
    .collect(Collectors.toList());

    这样?
    Corolin
        16
    Corolin  
       2023-08-10 17:39:41 +08:00
    好像 JsonPath 可以 反过来一层层去取?$.response.customerInfo[*]
    https://jsonpath.com/
    c3de3f21
        17
    c3de3f21  
       2023-08-10 18:13:10 +08:00
    得需要个 type 字段。。。
    c3de3f21
        18
    c3de3f21  
       2023-08-10 18:13:34 +08:00
    或者说需要一些 描述 json 本身的字段才行。
    mmdsun
        19
    mmdsun  
       2023-08-11 12:52:34 +08:00 via iPhone
    转对象处理,动态的用在对象里面用 map 声明 @JsonAnyGetter 、 @JsonAnySetter 即可。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5597 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 07:54 · PVG 15:54 · LAX 23:54 · JFK 02:54
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.