浅谈Java中JSON的序列化问题
2017-10-24 00:00
351 查看
在Java Web开发的过程中,时常会遇到与自己预期不一样的情况。有的时候静下心来自己去研究一番内在的原因还是很有趣的。这两天在写java web的时候,碰到了一个对象序列化的问题,问题大概是这样的:
上面是一个接口类,我们需要把这个类的对象序列化成json返回。那么在springmvc中,一般是这样操作的。
默认的话,返回ResponseBody,对象会直接序列化成json。这个时候,我们可以看一下返回的json。
显然,和我们预期想的不太一样,多了一个jsonstr字段。这个时候我在想,是不是springmvc的问题。结果仔细一想,springnvc之所以可以直接将对象序列化成json,其实是我们添加的配置文件在起作用,真正参与序列化工作的是jackson这个库。于是,我单独使用了jackson,结果返回的json字符串和之前是相同的,这下就可以肯定是,jackson这个库本身的设计问题了。
深入探讨
带着这份好奇,我把java中常用的json序列化的库都试了一下,看看是否都是这样。主流的库有jackson、fastjson和gson。
经过测试发现,jackson和阿里的fastjson返回的json字符串都带有一个jsonstr字段,唯独google的gson返回了我们预期的结果——只序列化对象的field。
于是我找了下这几个库的序列化原理:
jackson和fastjson
在序列化的时候,先利用反射找到对象类的所有get方法,接下来去get,然后小写化,作为json的每个key值,而get方法的返回值作为value。接下来再反射field,添加到json中。
gson
没有找到通俗的讲法,不过感觉应该就和getter方法无关吧。
所以,可以看大我们的AjaxJson类中存在这样一个getJsonStr,因此,jsonStr就作为key,序列化到json中了。
当然在jackson中,提供了相应的annotation,可以把这类方法忽略掉。在方法前加上@JsonIgnore 即可。
对此问题的理解
遇到问题的时候,千万不要忽略一些简单的地方,例如getter和setter方法。用getXXX的地方,可以用fetch等替代。
有时我们会在类中定义例如private int mAge的变量,而getter的方法是getAge()。显然我们希望在序列化的时候得到的key为age而非mAge,那么反射getter方法也就有它存在的意义了。
public class AjaxJson { private boolean success; private String msg; private Object obj; private Map<String, Object> attributes; //getter and setter public String getJsonStr() { JSONObject obj = new JSONObject(); obj.put("success", this.isSuccess()); obj.put("msg", this.getMsg()); obj.put("obj", this.obj); obj.put("attributes", this.attributes); return obj.toJSONString(); } }
上面是一个接口类,我们需要把这个类的对象序列化成json返回。那么在springmvc中,一般是这样操作的。
@RequestMapping(params = "/get") @ResponseBody public AjaxJson del(HttpServletRequest request) { AjaxJson json = new AjaxJson(); //省略业务操作 return json; }
默认的话,返回ResponseBody,对象会直接序列化成json。这个时候,我们可以看一下返回的json。
{ "success": "true", "Msg":"1", "obj":{ ... }, "attributes": null, "jsonStr":"{"success": "true","Msg":"1","obj":{...},"attributes": null,}" }
显然,和我们预期想的不太一样,多了一个jsonstr字段。这个时候我在想,是不是springmvc的问题。结果仔细一想,springnvc之所以可以直接将对象序列化成json,其实是我们添加的配置文件在起作用,真正参与序列化工作的是jackson这个库。于是,我单独使用了jackson,结果返回的json字符串和之前是相同的,这下就可以肯定是,jackson这个库本身的设计问题了。
深入探讨
带着这份好奇,我把java中常用的json序列化的库都试了一下,看看是否都是这样。主流的库有jackson、fastjson和gson。
经过测试发现,jackson和阿里的fastjson返回的json字符串都带有一个jsonstr字段,唯独google的gson返回了我们预期的结果——只序列化对象的field。
于是我找了下这几个库的序列化原理:
jackson和fastjson
在序列化的时候,先利用反射找到对象类的所有get方法,接下来去get,然后小写化,作为json的每个key值,而get方法的返回值作为value。接下来再反射field,添加到json中。
gson
没有找到通俗的讲法,不过感觉应该就和getter方法无关吧。
所以,可以看大我们的AjaxJson类中存在这样一个getJsonStr,因此,jsonStr就作为key,序列化到json中了。
当然在jackson中,提供了相应的annotation,可以把这类方法忽略掉。在方法前加上@JsonIgnore 即可。
对此问题的理解
遇到问题的时候,千万不要忽略一些简单的地方,例如getter和setter方法。用getXXX的地方,可以用fetch等替代。
有时我们会在类中定义例如private int mAge的变量,而getter的方法是getAge()。显然我们希望在序列化的时候得到的key为age而非mAge,那么反射getter方法也就有它存在的意义了。
相关文章推荐
- java fastjson反序列化问题记录
- 关于数据序列化(5),定制FastJSON序列化(解决Java大Long类型js的Number接收丢失数据的问题,不序列化某些属性)
- 浅谈java对象转json,数字精确出现丢失问题
- 浅谈用Java微信公众号开发时向微信服务器发送JSON数据包返回47001错误码问题
- 关于json反序列化字符串为java对象时科学计数法和精度问题
- JSON转Date的序列化问题之解决方案(Java)
- 171207之java中的JSON序列化问题
- AJAX JSON中日期类型DateTime格式化的序列化自定义对象以及自定义类型参数的问题处理
- java Enum序列化问题
- json 序列化日期的问题
- 浅谈Java多线程的同步问题
- 浅谈Java多线程的同步问题
- Java Json/xml 序列化和反序列化 工具:JsonTools 和 simpleframework 附带实例
- JavaScriptSerializer 对 DateTime 数据类型的JSON序列化的问题
- 浅谈Java多线程的同步问题
- 浅谈Java多线程的同步问题
- 关于JAVA序列化的几个问题
- json2.js 不能反序列化时间属性问题
- Java对象序列化成JSON对象
- 浅谈Java多线程的同步问题