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

Json 解析丢失子类信息

  •  
  •   nnegier · 2023-07-07 08:12:58 +08:00 · 2433 次点击
    这是一个创建于 513 天前的主题,其中的信息可能已经有所发展或是发生改变。

    子类们的共同父类:BasePlugin

    生成 Json ,子类信息都可以很好的输出

    String json = new Gson().toJson(list);
    

    但是,如果从 Json 中解析泛型类,它的子类的信息就获取不到,无法类型强转

    Type type = new TypeToken<List<BasePlugin>>() {
    }.getType();
    return new Gson().fromJson(json, type);
    

    这个有可能解决吗?

    第 1 条附言  ·  2023-07-07 20:03:34 +08:00
    #6 6 楼答案有效
    12 条回复    2023-07-11 14:07:53 +08:00
    chendy
        1
    chendy  
       2023-07-07 08:20:25 +08:00
    koloonps
        2
    koloonps  
       2023-07-07 09:08:40 +08:00
    new ObjectMapper().readValue("", new TypeReference<Object>() {
    @Override
    public Type getType() {
    return super.getType();
    }
    })
    AoEiuV020JP
        3
    AoEiuV020JP  
       2023-07-07 10:08:47 +08:00
    讲道理,仔细想想, 如果可以从父类泛型这样得到子类的属性,那人家直接内置一个,
    Type type = new TypeToken<List<Object>>() {
    }.getType();
    压根都不需要暴露出 TypeToken 了,

    这问题一定是无解的, 具体类型必须有个渠道提供给 json 框架,
    加个 if else 判断然后 new 不同的 TypeToken 吧,
    或者这个 type 改从外部传入,
    MozzieW
        4
    MozzieW  
       2023-07-07 10:17:16 +08:00
    楼上的回复解决的范型 List ,OP 要的是范型 List+子类。
    实践上,应该不能这么操作。解决范型 List 反序列话时候,我们是通过带入一个 Type 指定类型,解决类型丢失问题。而 OP 场景下,还多了一个子类型丢失问题。
    最简单的方法,不要用子类,一个类接收全部参数,通过 type 区分行为,后续通过设计模式、switch 、if 代码 解决代码复用、逻辑问题。
    其他方法:JSON 序列化时引入子类 type ,反序列化时先转为 map ,再根据 type 的值转为子类。
    xiangyuecn
        5
    xiangyuecn  
       2023-07-07 10:42:33 +08:00
    你实例化一个父类的实例,怎么可能会包含子类才有的属性🐶
    shily
        6
    shily  
       2023-07-07 11:18:59 +08:00   ❤️ 1
    这个问题分两种情况:
    1. 列表中的元素是同一种类型的,这样只需要调整一下类型信息就行了 new TypeToken<List<PluginA>>() {}.getType(); 来获取单一类型的 list ,这样 list 中的元素就是 PluginA ;
    2. 列表中的元素是混合类型的,混合了类型 PluginA 和 类型 PluginB ,这样的话,需要自己注册反系列化器 JsonDeserializer 来识别类型;

    wqhui
        7
    wqhui  
       2023-07-07 11:43:23 +08:00
    反序列化的时候填了父类,解析的时候怎么知道你的子类有什么属性,或者说如果有一堆子类怎么知道装载成那个子类才是对的。
    反序列化时需要想办法指定子类,比如参考 mongodb ,在序列化结果加上序列化的 class ,反序列化根据这个 class 来弄;比如在代码中使用注解标记 List 中的范型具体 class 是什么。
    oneisall8955
        8
    oneisall8955  
       2023-07-07 12:13:35 +08:00 via Android
    fastjson 携带类信息,或许可以解决

    https://blog.csdn.net/xl_1803/article/details/128375110

    ( csdn🐶)

    但印象这个有安全性问题
    Leon406
        9
    Leon406  
       2023-07-07 12:45:41 +08:00
    发下写的 gson 工具类, 可以参考


    import com.google.gson.Gson;
    import com.google.gson.JsonObject;
    import com.google.gson.reflect.TypeToken;

    import java.lang.reflect.Type;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;

    /**
    * <p>description:Gson 单例</p>
    * <p>author:Leon</p>
    * <p>date:2019/2/25 0025</p>
    * <p>e-mail: [email protected]</p>
    */
    public class GsonUtils {
    private static final GsonUtils INSTANCE = new GsonUtils();
    private Gson gson;

    private GsonUtils() {
    gson = new Gson();
    }

    public static GsonUtils get() {
    return INSTANCE;
    }

    public Gson gson() {
    return gson;
    }

    public String toJson(Object obj) {
    return gson.toJson(obj);
    }


    public <D> D fromJson(String json, Class<D> clazz) {
    return gson.fromJson(json, clazz);
    }

    public <D> List<D> jsonToList(String json, Class<D[]> clazz) {
    D[] array = gson.fromJson(json, clazz);
    return Arrays.asList(array);
    }

    public <D> ArrayList<D> jsonToArrayList(String json, Class<D> clazz) {
    Type type = new TypeToken<ArrayList<JsonObject>>() {
    }.getType();
    ArrayList<JsonObject> jsonObjects = gson.fromJson(json, type);

    ArrayList<D> arrayList = new ArrayList<>();
    for (JsonObject jsonObject : jsonObjects) {
    arrayList.add(gson.fromJson(jsonObject, clazz));
    }
    return arrayList;
    }
    }
    Helsing
        10
    Helsing  
       2023-07-07 13:30:05 +08:00 via iPhone
    可以换 kotlin 试试,有 reified 关键字
    OpenJdk
        11
    OpenJdk  
       2023-07-11 14:03:49 +08:00
    不知道你用的什么 JSON 序列化工具。
    OpenJdk
        12
    OpenJdk  
       2023-07-11 14:07:53 +08:00
    不知道你用的什么 JSON 序列化工具。
    但是 Jackson 是通过在父类上打注解以字段值判定的形式来指定反序列化使用哪个具体的子类。
    看看 @JsonTypeInfo 和 @JsonSubTypes 注解。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2701 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 09:29 · PVG 17:29 · LAX 01:29 · JFK 04:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.