结构不固定的 json 值要怎么反序列化成对象比较好? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
x97bgt
V2EX    Java

结构不固定的 json 值要怎么反序列化成对象比较好?

  •  1
     
  •   x97bgt 2021-09-01 14:12:17 +08:00 3759 次点击
    这是一个创建于 1512 天前的主题,其中的信息可能已经有所发展或是发生改变。

    json 里面有互斥的字段,要怎么序列化成对象?

    比如下面的例子里,要么只有refund字段,要么只有purchase,而且两个字段里的结构是不一样的。

    { "id": "1234567890", "amount": 100, "refund" { "date": "2021-04-23T18:25:43.511Z", "confirmed": true, "refund_id": 1234456 } } { "id": "1234567890", "amount": 100, "purchase": { "date": "2021-04-23T18:25:43.511Z", "purchase_id": 789621 } } 

    现在到的最粗暴的办法,是把每个字段都塞进对象。但这太难看了,而且容易造成混乱。

    这种结构下,要怎么设计对象的结构比较好?

    34 条回复    2021-09-02 13:15:06 +08:00
    2kCS5c0b0ITXE5k2
        1
    2kCS5c0b0ITXE5k2  
       2021-09-01 14:17:57 +08:00
    应该要好好想想 为什么 id 能有重复的吧.
    xiaokongwu
        2
    xiaokongwu  
       2021-09-01 14:19:27 +08:00
    @emeab 人家只是随便写个例子吧
    binux
        3
    binux  
       2021-09-01 14:20:56 +08:00 via Android
    两个类,反序列化之前判断一下是哪个。
    fkmc
        4
    fkmc  
       2021-09-01 14:21:49 +08:00
    加 type 结构保持一致
    xiaokongwu
        5
    xiaokongwu  
       2021-09-01 14:23:34 +08:00
    要不用 map 接吧……
    jenlors
        6
    jenlors  
       2021-09-01 14:24:10 +08:00
    结构合并在一起,某些值可为空
    micean
        7
    micean  
       2021-09-01 14:26:21 +08:00
    自己写个自定义的反序列化适配就可以了,但是还不如塞 2 个对象呢
    YJi
        8
    YJi  
       2021-09-01 14:31:38 +08:00
    要是非用一个类,感觉只能枚举所有字段了.. (蹲一个其他方案
    thtznet
        9
    thtznet  
       2021-09-01 14:35:32 +08:00
    动态
    BigDogWang
        10
    BigDogWang  
       2021-09-01 14:36:13 +08:00
    接口设计的不合理吧,难不成你要用的时候还要判断下这两个对象哪个不为 null ?
    lower
        11
    lower  
       2021-09-01 14:39:43 +08:00
    type: 区分类型
    data:存数据,直接用 Object 或者泛型
    cpstar
        12
    cpstar  
       2021-09-01 14:40:02 +08:00
    json 本来就不是固定结构的,用编程语言的话叫不是强类型
    反序列化到对象,肯定得是两个类了,一个类是 refund,一个类是 purchase,至于这两个类是否从一个 super class 中派生,那是另外一个事情了。
    然后上工厂模式,factory.unserialize(json)
    Puteulanus
        13
    Puteulanus  
       2021-09-01 14:40:10 +08:00
    早点判断早点分开比较好吧,感觉是过度抽象了,两个东西内容不一样硬要捏在一起的话,后面写会到处是 if 判断的
    sankemao
        14
    sankemao  
       2021-09-01 14:44:43 +08:00
    加一个 type 用以区分
    chendy
        15
    chendy  
       2021-09-01 14:46:27 +08:00
    既然传进来之后要做区分,为什么不直接在接口一层就做区分呢?
    不过确实存在一些一个接口怼所有类型的情况(比如一些 webhook ),我的做法是做一个包含所有可能字段的大类接参数进来(还好没有冲突)然后区分类型转换成需要的类型然后传给对应的业务
    qinxi
        16
    qinxi  
       2021-09-01 14:46:28 +08:00
    加个 type 区分一下 然后用多态 JsonSubTypes
    Kilerd
        17
    Kilerd  
       2021-09-01 15:20:48 +08:00 via iPhone
    rust 里面的 enum 可以很好的处理这种情况。其他语言就只能自己些 deserializer 去判断 type 了
    x97bgt
        18
    x97bgt  
    OP
       2021-09-01 15:25:47 +08:00
    @wccc
    @lower
    @sankemao
    @qinxi
    加一个`type`和`data`,`type`用于判断类型,`data`则是一个抽象类或 Object,使用的时候强制转换。是这样对么?
    zhady009
        19
    zhady009  
       2021-09-01 16:11:44 +08:00
    感觉类设计有点不太合理
    建议还是根据 refund 字段是否为空来分组分开来分别序列化成对应的类型
    Jooooooooo
        20
    Jooooooooo  
       2021-09-01 16:16:09 +08:00
    弄个 type 呀.
    bnm965321
        21
    bnm965321  
       2021-09-01 16:17:15 +08:00
    union type. 在 TS 里面也能很简单的处理
    x97bgt
        22
    x97bgt  
    OP
       2021-09-01 16:31:50 +08:00
    @binux 但是方法的返回值就只有一个类型啊。。
    ysc3839
        23
    ysc3839  
       2021-09-01 17:07:09 +08:00
    如果是 C++ 的话,我会选择定义两个 struct,然后用 std::variant 。
    goHomeAdmin
        24
    goHomeAdmin  
       2021-09-01 17:07:12 +08:00
    data {
    type_1: {},
    type_2: {},
    }

    protobuf 中的 one of 使用
    ysc3839
        25
    ysc3839  
       2021-09-01 17:11:22 +08:00
    Java 的话,我会选择把两个字段都写进去,允许 null 。
    Duolingo
        26
    Duolingo  
       2021-09-01 17:23:56 +08:00
    这不是用一个类就能解决的么
    passerbytiny
        27
    passerbytiny  
       2021-09-01 17:32:46 +08:00 via Android
    你这个不管对应到类还是对应到关系数据,都是两种数据类型,这就不要再想反序列化成一个类了。
    passerbytiny
        28
    passerbytiny  
       2021-09-01 17:36:14 +08:00 via Android
    这种结构不稳定的数据格式,是符合 JSON 规范和接口数据规范的,但不符合面向对象数据格式,建议不要做反序列化,直接当成 JSON 读取,用 jsonpath 的形式
    jiorix
        29
    jiorix  
       2021-09-01 17:57:17 +08:00
    类设计可以更抽象点,建议把差异的字段抽象为值。
    james2013
        30
    james2013  
       2021-09-01 20:14:18 +08:00
    {
    "id": "1234567890",
    "amount": 100,
    "refund": {
    "date": "2021-04-23T18:25:43.511Z",
    "confirmed": true,
    "refund_id": 1234456
    }
    "purchase": {
    "date": "2021-04-23T18:25:43.511Z",
    "purchase_id": 789621
    }
    }

    {
    "id": "1234567890",
    "amount": 100,
    "purchase": {
    "date": "2021-04-23T18:25:43.511Z",
    "purchase_id": 789621
    }
    }
    james2013
        31
    james2013  
       2021-09-01 20:15:43 +08:00
    类中放 refund 和 purchase2 个子类就可以了
    lululau
        32
    lululau  
       2021-09-01 22:39:29 +08:00
    class RootEnt {
    String id;
    int amount;
    RefundEnt refund;
    PurchaseEnt pruchase;
    }
    mingl0280
        33
    mingl0280  
       2021-09-02 04:07:46 +08:00 via Android
    class Json
    {
    string id;
    int amount;
    Purchase purchase;
    Refund refund;
    };
    rububio
        34
    rububio  
       2021-09-02 13:15:06 +08:00 via Android
    当然是用 Discriminate Union 啊。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     4448 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 38ms UTC 01:03 PVG 09:03 LAX 18:03 JFK 21:03
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86