点击上方蓝色字体,选择“设为星标”
回复”666“获取面试宝典不知道你们发现没有,你写完的程序无论当时怎么测试,过一段时间总会出 Bug 。再说一个每天都在发生的例子:在你写完一篇博客后,立即检查的话,总是查不出自己写的错别字。
据说这些都包含有一些大脑对当下事物处理的逻辑在里边,而且还有心理学因素在里边,我也不懂。反正现在就是程序出 Bug 了!出 Bug 了!!Bug !!!
事情是这样的,客户端请求服务器开放接口时,我们是以 JSON 字符串的形式返回的,这时候本来正常返回形式是这样:
{
"name": "mafly",
"age": "18",
"sex": "男"
}
但这个名字叫Mafly的人他不想让你知道他是男是女。就没填性别,程序中默认赋值为 null了,JSON 序列化时就发生了意想不到的事儿。
重现一下那个 Bug
用于转换Java对象为 Json 字符串和把 Json 字符串转换为对象的工具类有很多,Gson、Jackson、FastJson等,我们用的是 Gson, 它是 Google 开发的,还据传说它的性能比较强大一些。嗯,对,我们用的就是这个。先看示例代码:
public static void main(String[] args) {
HashMap map = new HashMap();
map.put("name", "mafly");
map.put("age", "18");
map.put("sex", null);
String jsonString = new Gson().toJson(map);
System.err.println(jsonString);
}
你猜会输出上面那段我们预期的 Json 串吗?然而并不会。
![bd605ce7caa2776d98ad8c9b4d591f19.png](https://i-blog.csdnimg.cn/blog_migrate/e3dc2a71ebb22431d22cd9a2956ac428.jpeg)
就是这个当 Sex=null时,用 Gson 的tojson方法会把 null 值忽略,从而序列化之后输出不包含这个属性值的 Json 串。其实我们的预期是输出 {"sex": ""} 或 {"sex": null}, 那怎么做呢?
通过搜索引擎发现,网上大概存在以下三种解决方案:
- 调用 toJson(Object src, Type typeOfSrc, JsonWriter writer) 方法
- 注册自定义 TypeAdapter
- 设置 serializeNulls 属性值(推荐)
前两种方式我没测试,推荐第三种方式,简单方便,源码如下:
GsonBuilder gsonBuilder = new GsonBuilder();
String jsonString1 = gsonBuilder.serializeNulls().create().toJson(map);
System.err.println(jsonString1);
输出符合我们的需求了, {"sex": null},如图:
![8f63801fe3293bee1dcb1e2af2c92c98.png](https://i-blog.csdnimg.cn/blog_migrate/a1987f160b2462e2819d8ec945a3d41b.jpeg)
简单转到源码看了看,除了这一个设置还有很多,真是太方便了。调用serializeNulls()后, Gson 设置 serializeNulls 属性值为 true,默认是false,源码:
public GsonBuilder serializeNulls() {
this.serializeNulls = true;
return this;
}
重新认识一下 Gson
我看了几行 Gson 的源码后,我发现它可配置及特性多的数不胜数,可以用@SerializedName注解给属性重命名,用@Expose注解标识属性不进行序列化,支持 Map 的 key 为复杂对象的形式,日期类型转化为特定格式,还有区分版本进行显示,这些在日常项目中都极常用到,只不过好像我们之前都是自己实现的。
我简单建立了一个 UserInfo 实体类,里边包含了username、age、sex这三个属性值。试着测试了一下其中一两个:
1.@Expose 想让谁输出谁输出,注解代码如图:
![3364a8cf19a75b48db313bf19cddc57f.png](https://i-blog.csdnimg.cn/blog_migrate/8eba8f6e6ce9c04ad79a7f0f2fa42c30.jpeg)
设置excludeFieldsWithoutExposeAnnotation(),看下面第三行是输出:
![1d2b0f824d3e9e15b2cce3b7cb618b86.png](https://i-blog.csdnimg.cn/blog_migrate/40da54a3413394739fa8fd582b09e714.jpeg)
2.@SerializedName 想怎么显示怎么显示,注解代码如图:
![068c2274b35a05b5526b7992b67c221c.png](https://i-blog.csdnimg.cn/blog_migrate/77b387a42977c798729793c2043094b7.jpeg)
我想把age再 Json序列化时显示maflyAge,现在就可以了,输出如下图:
![875c5e434c18a983ea550b0096d08a02.png](https://i-blog.csdnimg.cn/blog_migrate/ba2dab88b53acbfc815980c0c6b0267f.jpeg)
3.@Since、@Until 不同版本不同数据,注解代码如图:
![3af278cf6ab4ca9d141e4c656c101c29.png](https://i-blog.csdnimg.cn/blog_migrate/309bb037c8765525e1ead5c0861128dd.jpeg)
这里要设置setVersion(3.2),@Since标注的在 3.2 版本或之后才会输出,@Until标注的只在 3.2 版本前才有。效果输出如下图:
![e8dc59f8da7e79389903b9451d89b034.png](https://i-blog.csdnimg.cn/blog_migrate/cb43c375a08b3d48171801eb6071ea2f.jpeg)
当然,还有好多特性呢,比如字段首字母大写阿、结果格式化阿等等,我这里抛个砖,剩下的有需要的可以试试。
总结一下
这是由于一个 Json 序列化输出后发现的小 Bug ,也可以说不能算 Bug ,因为是我们对于自己使用的工具类并不了解导致的,所以,去试着了解你使用的任何一个开源工具类或项目,对于遇到的问题可以很好的得到解决,从而也可以提升自己吧。
来源 | https://urlify.cn/YfuQVz![6dac186b35bdfb00fddafddd25597b61.gif](https://i-blog.csdnimg.cn/blog_migrate/343e254534c05513dd721f753c420876.gif)
面试官问:MySQL的自增ID用完了,怎么办?
ArrayList插入1000w条数据之后,我怀疑了jvm...
蚂蚁二面,面试官问我零拷贝的实现原理,当场懵了…
最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ♡