相信大家在代码编写中都用过Gson和fastjson吧,用来进行 Java对象和json字符串之间的转换。

本篇文章就主要介绍博主在工作中使用这两款工具时遇到的坑和对应的解决办法。

觉得有用的可以点个赞哈~

1.前言

看了下我上一篇文章的发布时间,已然是两个月前了,这两个月工作确实很忙,加班也不少,空闲的时间都去研究别的技术了(后面会写文章),这次先用此篇文章记录我这段时间工作中遇到的坑,其实写文章的主要目的也是想记录一下问题,便于帮助他人也便于自己以后查看,废话不多说,开始说明问题~

2.Gson和fastjson介绍

Google Gson是一个简单的基于Java的库,用于将Java对象序列化为JSON,反之亦然。 它是由Google开发的一个开源库。

fastjson和Gson一样的作用,但其是由国内阿里巴巴开发的一款工具。

fastjson比Gson快很多倍,也由于其是国内阿里开发,被大量使用,但也频繁被爆出问题,官方也紧急修复更新版本了。但是实际使用中,这两款工具也各有各的坑,合理的根据自己需要的去选择工具即可。

3.问题说明及解决

下面将先说明我遇到的坑,然后会给出相应解决办法,当然大家可以摸索更好的解决方式~

3.1 Gson会将Integer类型转为Double

场景:一个业务需求的编辑功能,我需要把查询后得到的id隐藏在页面上,以便保存时根据id去修改数据。但自测时发现传到页面上的值是double类型,但数据库中是int,这就造成了无法修改的问题,一一排查问题后我发现是Gson搞的鬼

解决办法1:使用fastjson即可解决,引入依赖后代码使用如下(推荐):

Map<String,Object> map = JSONObject.parseObject(result,Map.class);

解决方法2:将对象中的Integer类型改成String类型,这样就不会被自动转换了(根据自己业务情况使用)

解决方法3:在定义Gson时直接定义类型,代码如下:

private static Type typeToken = new TypeToken<TreeMap<String, Object>>(){}.getType();
Gson gson = new GsonBuilder()
.registerTypeAdapter(
new TypeToken<TreeMap<String, Object>>(){}.getType(),
new JsonDeserializer<TreeMap<String, Object>>() {
@Override
public TreeMap<String, Object> deserialize(
JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException { TreeMap<String, Object> treeMap = new TreeMap<>();
JsonObject jsonObject = json.getAsJsonObject();
Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for (Map.Entry<String, JsonElement> entry : entrySet) {
Object ot = entry.getValue();
if(ot instanceof JsonPrimitive){
treeMap.put(entry.getKey(), ((JsonPrimitive) ot).getAsString());
}else{
treeMap.put(entry.getKey(), ot);
}
}
return treeMap;
}
}).create();

实际代码中调用:

Map<String, Object> params = gson.fromJson(result, typeToken);

3.2 Gson不序列化匿名内部类

场景:完成任务接口时写了测试类来测接口,初始化Map集合的时候用了如下比较优雅的方式:

Map<String, String> map = new HashMap<String, String>() {
{
put("logNo", "123456");
put("reqTime", "20210607");
}
};
Gson gson = new Gson();
System.out.println(gson.toJson(map));

但是运行测试类输出结果以后会发现为null。这是因为此种方式生成的Map是匿名内部类的实例,也就是new出来的map没有类名。

查询相关文章可知:内部类的适配器会生成对外部类/实例的隐式引用,会导致循环引用。所以结论为:Gson不会序列化匿名内部类。

解决方法:使用fastjson就不会出现这种问题,可成功序列化转为json数据

看到这里是否觉得Gson出现的问题,fastjson都能解决,那下面就介绍下fastjson在实际应用中的坑。

3.3 fastjson会将数据顺序改变

场景:在对接其他公司接口时往往都需要加密解密并签名验签,为了防止传输过程中数据被篡改,主要是为了安全。此时json传输的数据顺序则是重要的,如果被打乱则会解密验签失败,我在用fastjson时就出现了这种问题,一度头疼~

解决方法1:解析返回数据时增加参数不调整顺序(推荐)

此时你的fastjson版本应该为1.2.3以上

	<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.3</version>
</dependency>

然后在解析数据时增加 Feature.OrderedField 参数即可

FrontJsonResponse frontJsonResponse = JSONObject.parseObject(response,FrontJsonResponse.class, Feature.OrderedField);

解决方法2:使用Gson解析数据即可,不会改变数据顺序

Gson gson = new Gson();
FrontJsonResponse frontJsonResponse = gson.fromJson(response,FrontJsonResponse.class)

3.4 fastjson会将字段首字母变为小写

场景:在对接其他公司接口时,文档中字段名称多为大写字母(如:FILE_NM等)如果自己想定义对象实体来序列化的话,使用fastjson就会在上送时将实体中每个属性的首字母变为小写(如:fILE_NM),这样上送则肯定会出问题,可以用以下方法解决:

解决方法1:在属性名加上 @JSONField(name = "") 注解即可(推荐)

@JSONField(name = "FILE_NM")
private String FILE_NM;

解决方法2:序列化时增加参数 new PascalNameFilter() ,会将首字母强制转换为大写。

JSON.toJSONString(bean,new PascalNameFilter());

3.5 fastjson不会将多层json转换为Map

场景:在对接第三方公司接口验签时,使用fastjson将返回数据转换为Map,再去生成待签名串验签时发现验签失败,查询后得知和第三方签名是生成的串不一致,因为处理方式不同,具体场景请看下面示例:

    public static void main(String[] args) {
String str = "{\"result\":{\"user_info\":{\"id\":14390753,\"sex\":1},\"complete_status\":0},\"errcode\":0}";
Map<String,Object> fastMap = JSONObject.parseObject(str, Map.class);
System.out.println("fastMap====="+fastMap);
Gson gson = new Gson();
Map<String,Object> gsonMap = gson.fromJson(str,Map.class);
System.out.println("gsonMap====="+gsonMap);
}

以上代码输出结果为:

fastMap====={result={"user_info":{"sex":1,"id":14390753},"complete_status":0}, errcode=0}
gsonMap====={result={user_info={id=1.4390753E7, sex=1.0}, complete_status=0.0}, errcode=0.0}

对比处理方式和实际结果就可以知道,如果json字符串里有多层json对象,使用fastjson时并不会处理里层的json,只会将外层json数据转换为Map,而使用Gson时会将符合json格式的数据都转换为Map。

最后跟第三方确认以后,因为他们不同接口有不同处理方式,我们这边只能兼容(因为他们改不了,怕影响别的使用方),根据不同接口去判断该用fastjson还是用Gson解析返回的数据再进行验签(真的...一言难尽...)

所以遇到这种情况时,要确定对方是以什么方式来处理,我们这边再确定用什么方式来接,这也是这两种工具的一个不同点。

4.总结

实际开发过程中遇到以上问题就很头疼,如果不一步一步debug看代码输出结果,根本不会想到是json转换工具的问题,但两款工具确实各有各的优势,我觉得选择适合自己业务代码的就是最好的,这些问题也都能解决,也不是用不了,还是看解决方法而已,遇到的这些问题我都会记录下来,等以后碰到类似问题了就能直接解决,这样也不错。

浅谈Gson和fastjson使用中的坑的更多相关文章

  1. 浅谈html5 video 移动端填坑记

    这篇文章主要介绍了浅谈html5 video 移动端填坑记,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 本文介绍了html5 video 移动端填坑记,分享给大家,具体 ...

  2. 浅谈如何写出一个让(坑)人(王)很(之)难(王)发现的bug

    该文章内容来自脚本之家,原文链接:https://www.jb51.net/news/598404.html 程序员的日常三件事:写bug.改bug.背锅.连程序员都自我调侃道,为什么每天都在加班?因 ...

  3. Android应用安全开发之浅谈加密算法的坑

      <Android应用安全开发之浅谈加密算法的坑> 作者:阿里移动安全@伊樵,@舟海 阿里聚安全,一站式解决应用开发安全问题     Android开发中,难免会遇到需要加解密一些数据内 ...

  4. 浅谈Android Studio3.0更新之路(遇坑必入)

    >可以参考官网设置-> 1 2 >> Fantasy_Lin_网友评论原文地址是:简书24K纯帅豆写的我也更新一下出处[删除]Fa 转自脚本之家 浅谈Android Studi ...

  5. 【转载】浅谈大规模k8s集群关于events的那些坑

    原文链接:一流铲屎官二流程序员[浅谈大规模k8s集群关于events的那些坑] 背景 随着k8s集群规模的增加,集群内的object数量也与日俱增,那么events的数量也会伴随其大量增加,那么当用户 ...

  6. 浅谈Hybrid技术的设计与实现第三弹——落地篇

    前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...

  7. 重新学习MySQL数据库6:浅谈MySQL的中事务与锁

    『浅入深出』MySQL 中事务的实现 在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇 ...

  8. 浅谈Hybrid技术的设计与实现第二弹

    前言 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 浅谈Hybrid技术的设计与实现第三弹——落地篇 接上文:浅谈Hybrid技术的设计与实现(阅读本文前,建议阅读这个先) ...

  9. 浅谈对Spring Framework的认识

    Spring Framework,作为一个应用框架,官方的介绍如下: The Spring Framework provides a comprehensive programming and con ...

随机推荐

  1. hdu5062 简单题

    题意:       求区间逆序数的个数,逆序数增加了个要求就是必须要是先升序在降序例如12321或者123321这样的. 思路:        水题直接写就行了,数据范围不大,估计直接求也不会超时,我 ...

  2. xposed结合Zygote分析

    android中zygote相信大家都很熟悉,它执行的函数是app_main.cpp,而xposed主要实现的就是替换app_main.cpp.所以在分析xposed时有必要来认识下zygote.好了 ...

  3. 在进程空间使用虚拟内存(Windows 核心编程)

    虚拟内存空间 如今的 Windows 操作系统不仅可以运行多个应用程序,还可以让每一个应用程序享受到约 4 GB 的虚拟内存空间(包括系统占用),假如内存为 4 GB 的话.那为什么 Window 可 ...

  4. Windows PE资源表编程(枚举资源树)

    资源枚举 写一个例子,枚举一个PE文件的资源表.首先说下资源相关的作为铺垫. 1.资源类型也是PE可选头中数据目录的一种.位于第三个类型. 2.资源目录分为三层.第四层是描述文件相关的.这些结构是按照 ...

  5. 【mybatis】mybatis分页拦截器搭配bootstrap-table使用

    提前说明: 这一种方式已被我自己pass掉了,已经被新的方式迭代了.但是记录下自己曾经的成果还是有必要的,而且里面的思想还是不变的,另外技术不就是在不断地迭代中升级吗.千万不要想着一步完美,那样会让你 ...

  6. PHP 通用格式化调试函数

    /** * 打印调试函数 * @param $content * @param $is_die */function pre($content, $is_die = true){ header('Co ...

  7. 敏杰开题——软工团队项目选择与NABCD分析

    这是一篇软件工程课程博客 Q A 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 团队项目选择 我们在这个课程的目标是 团队协作实践敏捷开发 这个作业在哪个具 ...

  8. Java开发人员最容易出现的几类错误

    一.把数组转成ArrayList List<String> list = Arrays.asList(arr); //以下带伪代码来自Arrays类中public static <T ...

  9. 成功的多项目管理都有哪些"制胜之道"?

    实施多项目管理,一个重要原因就是提高项目的效率和管理水平.除了满足时间.成本.业绩和客户需求之外,项目管理办公室(PMO)经理的预期产出还包括有效利用组织资源.下面是影响多项目管理成功的几个关键因素, ...

  10. Map 实现类之一:HashMap

    Map 实现类之一:HashMapHashMap是 Map 接口 使用频率最高的实现类.允许使用null键和null值,与HashSet一样,不保证映射的顺序.所有的key构成的集合是Set:无 ...