x97bgt
V2EX  ›  Java

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

  •  1
     
  •   x97bgt · Sep 1, 2021 · 4624 views
    This topic created in 1892 days ago, the information mentioned may be changed or developed.

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

    protobuf 中的 one of 使用
    ysc3839
    ysc3839
    Sep 1, 2021
    25
    Java 的话,我会选择把两个字段都写进去,允许 null 。
    Duolingo
    Duolingo
    Sep 1, 2021
    26
    这不是用一个类就能解决的么
    passerbytiny
    passerbytiny
    Sep 1, 2021 via Android
    27
    你这个不管对应到类还是对应到关系数据,都是两种数据类型,这就不要再想反序列化成一个类了。
    passerbytiny
    passerbytiny
    Sep 1, 2021 via Android
    28
    这种结构不稳定的数据格式,是符合 JSON 规范和接口数据规范的,但不符合面向对象数据格式,建议不要做反序列化,直接当成 JSON 读取,用 jsonpath 的形式
    jiorix
    jiorix
    Sep 1, 2021
    29
    类设计可以更抽象点,建议把差异的字段抽象为值。
    james2013
    james2013
    Sep 1, 2021
    30
    {
    "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
    james2013
    Sep 1, 2021
    31
    类中放 refund 和 purchase2 个子类就可以了
    lululau
    lululau
    Sep 1, 2021
    32
    class RootEnt {
    String id;
    int amount;
    RefundEnt refund;
    PurchaseEnt pruchase;
    }
    mingl0280
    mingl0280
    Sep 2, 2021 via Android
    33
    class Json
    {
    string id;
    int amount;
    Purchase purchase;
    Refund refund;
    };
    rububio
    rububio
    Sep 2, 2021 via Android
    34
    当然是用 Discriminate Union 啊。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2268 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 72ms · UTC 12:19 · PVG 20:19 · LAX 04:19 · JFK 07:19
    ♥ Do have faith in what you're doing.