json序列化的坑

在開發的過程當中,常常會碰到和本身預期不同的狀況。有的時候本身去研究一下仍是頗有趣的。這兩天在寫java web的時候,碰到了一個對象序列化的問題。java

問題重現

  1. public class AjaxJson {
  2. private boolean success;
  3. private String msg;
  4. private Object obj;
  5. private Map<String, Object> attributes;
  6. //getter and setter
  7. public String getJsonStr() {
  8. JSONObject obj = new JSONObject();
  9. obj.put("success", this.isSuccess());
  10. obj.put("msg", this.getMsg());
  11. obj.put("obj", this.obj);
  12. obj.put("attributes", this.attributes);
  13. return obj.toJSONString();
  14. }
  15. }

上面是一個接口類,咱們須要把這個類的對象序列化成json返回。那麼在springmvc中,通常是這樣操做的。web

  1. @RequestMapping(params = "/get")
  2. @ResponseBody
  3. public AjaxJson del(HttpServletRequest request) {
  4. AjaxJson json = new AjaxJson();
  5. //省略業務操做
  6. return json;
  7. }

默認的話,返回ResponseBody,對象會直接序列化成json。這個時候,咱們能夠看一下返回的json。spring

  1. {
  2. "success": "true",
  3. "Msg":"1",
  4. "obj":{
  5. ...
  6. },
  7. "attributes": null,
  8. "jsonStr":"{"success": "true","Msg":"1","obj":{...},"attributes": null,}"
  9. }

顯然,和咱們預期想的不太同樣,多了一個jsonstr字段。這個時候我在想,是否是springmvc的問題。結果仔細一想,springnvc之因此能夠直接將對象序列化成json,實際上是咱們添加的配置文件在起做用,真正參與序列化工做的是jackson這個庫。因而,我單獨使用了jackson,結果返回的json字符串和以前是相同的,這下就能夠確定是,jackson這個庫自己的設計問題了。json

深刻探討

帶着這份好奇,我把java中經常使用的json序列化的庫都試了一下,看看是否都是這樣。主流的庫有jackson、fastjson和gson。mvc

jackson和fastjson強依賴getter方法,底層試用反射。app

通過測試發現,jackson和阿里的fastjson返回的json字符串都帶有一個jsonstr字段,惟獨google的gson返回了咱們預期的結果——只序列化對象的field。測試

因而我找了下這幾個庫的序列化原理:fetch

  • jackson和fastjson
    在序列化的時候,先利用反射找到對象類的全部get方法,接下來去get,而後小寫化,做爲json的每一個key值,而get方法的返回值做爲value。接下來再反射field,添加到json中。
  • gson
    沒有找到通俗的講法,不過感受應該就和getter方法無關吧。

因此,能夠看大咱們的AjaxJson類中存在這樣一個getJsonStr,所以,jsonStr就做爲key,序列化到json中了。this

固然在jackson中,提供了相應的annotation,能夠把這類方法忽略掉。在方法前加上@JsonIgnore便可。google

我的理解

  • 遇到問題的時候,千萬不要忽略一些簡單的地方,例如getter和setter方法。同時也能夠必定程度畢業用到getXXX,能夠用fetch等替代。
  • 有時咱們會在類中定義例如private int mAge的變量,而getter的方法是getAge()。顯然咱們但願在序列化的時候獲得的key爲age而非mAge,那麼反射getter方法也就有它存在的意義了。
相關文章
相關標籤/搜索