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

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

  •  1
     
  •   x97bgt · 88 天前 · 2247 次点击
    这是一个创建于 88 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    protobuf 中的 one of 使用
    ysc3839
        25
    ysc3839   88 天前
    Java 的话,我会选择把两个字段都写进去,允许 null 。
    codingadog
        26
    codingadog   88 天前
    这不是用一个类就能解决的么
    passerbytiny
        27
    passerbytiny   88 天前 via Android
    你这个不管对应到类还是对应到关系数据,都是两种数据类型,这就不要再想反序列化成一个类了。
    passerbytiny
        28
    passerbytiny   88 天前 via Android
    这种结构不稳定的数据格式,是符合 JSON 规范和接口数据规范的,但不符合面向对象数据格式,建议不要做反序列化,直接当成 JSON 读取,用 jsonpath 的形式
    jiorix
        29
    jiorix   88 天前
    类设计可以更抽象点,建议把差异的字段抽象为值。
    james2013
        30
    james2013   88 天前
    {
    "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   88 天前
    类中放 refund 和 purchase2 个子类就可以了
    lululau
        32
    lululau   88 天前
    class RootEnt {
    String id;
    int amount;
    RefundEnt refund;
    PurchaseEnt pruchase;
    }
    mingl0280
        33
    mingl0280   87 天前 via Android
    class Json
    {
    string id;
    int amount;
    Purchase purchase;
    Refund refund;
    };
    rububio
        34
    rububio   87 天前 via Android
    当然是用 Discriminate Union 啊。
    关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   936 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 19:52 · PVG 03:52 · LAX 11:52 · JFK 14:52
    ♥ Do have faith in what you're doing.