Gson转换json数据为HashMap时long类型变为double问题解决

简介: 今天再使用Gson处理json数据的时候碰到了一个问题 , 当我使用如下代码解析json数据的时候 , requestTime就变为了double类型

问题你提描述

今天再使用Gson处理json数据的时候碰到了一个问题 , 当我使用如下代码解析json数据的时候 , requestTime就变为了double类型


Map<String , Object> sourceValueMap =  gson.fromJson(jsonData , new TypeToken<HashMap<String , Object>>(){}.getType());

400fa3b05b4fa95befa8da99cfcd93e4_5e46757b308249bfac93535e6cc7d408.png

蓝色框为原始数据 , 红色框为解析之后的数据


解决办法 :

再翻阅了众多资料之后 , 发现有两种解决办法

1.修改源码

2.添加指定类型的自定义解密工具

相对来说第二种解决办法显然更轻松


在上面的代码中,你可以测试网络中找到的其他解决方式,你会发现所有设置都失效了。


原因是,当你使用 Class 对象作为解析类型时,Gson 会转入你自定义的解析器,而使用 TypeToken 时,Gson 无法将传入的参数与绑定的 TypeToken 对应,最终使用默认解析器。


实现过程

创建自定义的 ObjectTypeAdapter 对象,并实现其工厂方法

public final class MapTypeAdapter extends TypeAdapter<Object> {
    public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
        @SuppressWarnings("unchecked")
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            if (type.getRawType() == Object.class) {
                return (TypeAdapter<T>) new MapTypeAdapter(gson);
            }
            return null;
        }
    };
    private final Gson gson;
    private MapTypeAdapter(Gson gson) {
        this.gson = gson;
    }
    @Override
    public Object read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        //判断字符串的实际类型
        switch (token) {
            case BEGIN_ARRAY:
                List<Object> list = new ArrayList<>();
                in.beginArray();
                while (in.hasNext()) {
                    list.add(read(in));
                }
                in.endArray();
                return list;
            case BEGIN_OBJECT:
                Map<String, Object> map = new LinkedTreeMap<>();
                in.beginObject();
                while (in.hasNext()) {
                    map.put(in.nextName(), read(in));
                }
                in.endObject();
                return map;
            case STRING:
                return in.nextString();
            case NUMBER:
                String s = in.nextString();
                if (s.contains(".")) {
                    return Double.valueOf(s);
                } else {
                    try {
                        return Integer.valueOf(s);
                    } catch (Exception e) {
                        return Long.valueOf(s);
                    }
                }
            case BOOLEAN:
                return in.nextBoolean();
            case NULL:
                in.nextNull();
                return null;
            default:
                throw new IllegalStateException();
        }
    }
    @Override
    public void write(JsonWriter out, Object value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        //noinspection unchecked
        TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass());
        if (typeAdapter instanceof ObjectTypeAdapter) {
            out.beginObject();
            out.endObject();
            return;
        }
        typeAdapter.write(out, value);
    }
}

使用自定义工厂方法取代 Gson 实例中的工厂方法。

public class GsonFactory {
    public static Gson getGson() {
        Gson gson = new GsonBuilder().create();
        try {
            Field factories = Gson.class.getDeclaredField("factories");
            factories.setAccessible(true);
            Object o = factories.get(gson);
            Class<?>[] declaredClasses = Collections.class.getDeclaredClasses();
            for (Class c : declaredClasses) {
                if ("java.util.Collections$UnmodifiableList".equals(c.getName())) {
                    Field listField = c.getDeclaredField("list");
                    listField.setAccessible(true);
                    List<TypeAdapterFactory> list = (List<TypeAdapterFactory>) listField.get(o);
                    int i = list.indexOf(ObjectTypeAdapter.FACTORY);
                    list.set(i, MapTypeAdapter.FACTORY);
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return gson;
    }
}

使用

e10c4bd7fad936bd934c27bd521b1bd7_cce4bedf64b2493da99ad86e5e37c207.png

这样的话问题完美解决 , 数据也一切正常

25cf0fb3381a8bf2e23a03c0805be34d_a1702cc3bfaf4732baf84064d3fa4b38.png

相关文章
计算 long long, long double 字节大小
【10月更文挑战第14天】计算 long long, long double 字节大小
304 7
|
XML JSON 数据可视化
数据集学习笔记(二): 转换不同类型的数据集用于模型训练(XML、VOC、YOLO、COCO、JSON、PNG)
本文详细介绍了不同数据集格式之间的转换方法,包括YOLO、VOC、COCO、JSON、TXT和PNG等格式,以及如何可视化验证数据集。
4105 1
数据集学习笔记(二): 转换不同类型的数据集用于模型训练(XML、VOC、YOLO、COCO、JSON、PNG)
|
JSON 前端开发 JavaScript
聊聊 Go 语言中的 JSON 序列化与 js 前端交互类型失真问题
在Web开发中,后端与前端的数据交换常使用JSON格式,但JavaScript的数字类型仅能安全处理-2^53到2^53间的整数,超出此范围会导致精度丢失。本文通过Go语言的`encoding/json`包,介绍如何通过将大整数以字符串形式序列化和反序列化,有效解决这一问题,确保前后端数据交换的准确性。
399 4
计算 long long, long double 字节大小
【10月更文挑战第13天】计算 long long, long double 字节大小。
206 4
|
JSON JavaScript Java
在Java中处理JSON数据:Jackson与Gson库比较
本文介绍了JSON数据交换格式及其在Java中的应用,重点探讨了两个强大的JSON处理库——Jackson和Gson。文章详细讲解了Jackson库的核心功能,包括数据绑定、流式API和树模型,并通过示例演示了如何使用Jackson进行JSON解析和生成。最后,作者分享了一些实用的代码片段和使用技巧,帮助读者更好地理解和应用这些工具。
799 0
在Java中处理JSON数据:Jackson与Gson库比较
|
JSON 人工智能 编译器
Go json 能否解码到一个 interface 类型的值
Go json 能否解码到一个 interface 类型的值
147 1
|
存储 Java
HashMap与LinkedHashMap类型集合
【8月更文挑战第4天】`HashMap` 是基于哈希表实现的键值对存储结构,提供快速的查找、插入和删除操作,但不保证元素顺序。适用于不关心顺序且需高效操作的场景。 `LinkedHashMap` 继承自 `HashMap`,保持了元素的插入或访问顺序。适合需要按特定顺序遍历元素的应用,如按添加顺序显示购物车商品。其操作效率与 `HashMap` 相近。
264 1
|
JSON 关系型数据库 MySQL
实时计算 Flink版产品使用问题之在使用CDAS语法同步MySQL数据到Hologres时,如果开启了字段类型宽容模式,MySQL中的JSON类型会被转换为什么
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
计算long long, long double 字节大小
计算long long, long double 字节大小。
261 3
|
存储 编译器 C++
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
401 0