Gson反序列化复杂数据结构

  • 操作环境:
    jdk8、gson 2.8.5
  • 实验代码
public class TestSerial {
    public static void main(String[] args) {
        Outer outer = new Outer();
        // JsonUtil是自己封装的一个json工具类。
        String json = JsonUtil.toJson(outer);
        Outer outer1 = JsonUtil.fromJson(json, new TypeToken<Outer>() {
        });
        System.out.println(outer1);
    }
    static class Outer {
        Inner inner = new Inner();
    }
    static class Inner {
        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

    }
}

JsonUtil相关代码

public static String toJson(Object target) {
        return toJson(target, null, false, null, null, EXCLUDE_FIELDS_WITHOUT_EXPOSE, PRETTY_PRINT);
    }
public static String toJson(Object target, Type targetType, boolean isSerializeNulls, Double version, String datePattern, boolean excludesFieldsWithoutExpose, boolean prettyPrint) {
        if (target == null) {
            return EMPTY_JSON;
        }
        GsonBuilder builder = new GsonBuilder().setExclusionStrategies(new FilterExclusionStrategy());
        if (isSerializeNulls) {
            builder.serializeNulls();
        }

        if (prettyPrint) {
            builder.setPrettyPrinting();
        }

        if (version != null) {
            builder.setVersion(version.doubleValue());
        }

        if (isEmpty(datePattern)) {
            datePattern = DEFAULT_DATE_PATTERN;
        }

        builder.setDateFormat(datePattern);
        if (excludesFieldsWithoutExpose) {
            builder.excludeFieldsWithoutExposeAnnotation();
        }

        String result = "";

        Gson gson = builder.create();

        try {
            if (targetType != null) {
                result = gson.toJson(target, targetType);
            } else {
                result = gson.toJson(target);
            }
        } catch (Exception ex) {
            log.error("目标对象 " + target.getClass().getName() + " 转换 JSON 字符串时,发生异常!", ex);
            if (target instanceof Collection || target instanceof Iterator || target instanceof Enumeration || target.getClass().isArray()) {
                result = EMPTY_JSON_ARRAY;
            } else {
                result = EMPTY_JSON;
            }

        }

        return result;
    }
  • 问题结果截图
    Gson反序列化后数据结构变了
  • 问题分析
    我已经声明了Inner类里属性map的数据结构为ConcurrentHashMap为什么在反序列化的时候变成了LinkedTreeMap呢?顺着代码追了一遍发现,这个Map是Gson包下自己定义的一个数据结构。如果没有给嵌套对象指定类型,默认的结果就是LinkedTreeMap。
  • 解决方案
  1. 使用策略模式,给自己定义的待反序列化的类实现自己独有的反序列化方法,其主要的接口为:JsonDeserializer
    伪代码:
public class MyDeSerial implements JsonDeserializer<TestSerial.Outer> {
    @Override
    public TestSerial.Outer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return null;
    }
}
  1. 不使用泛型,可以避免泛型擦除的问题;即将Inner类中的属性,直接生命成对应的数据结构类型,而不使用泛型接口。代码如下:
static class Inner {
        ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
    }
  • 关于序列化接口的使用,个人觉得它的应用场景只有两个
  1. 需要持久化到文件中
  2. 需要进行流传输的
  3. 诸如Json这样的操作,我们是没有必要实现序列化接口的
  • 总结:
  1. Gson不需要相关类实现Serializable接口
  2. Gson反序列化嵌套类型的复杂对象会有泛型擦除的可能
  3. 遇事不要慌、冷静思考终有答案!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值