天天看點

fastjson,請注意大小寫

前言:fastjson先生(後稱之為F先生)由阿裡巴巴集團榮譽出品,我的記憶中,偉大的阿裡巴巴對于程式設計界,能夠稱之為貢獻的也僅此而已,可見我是多麼的孤陋寡聞。我的項目中也用到了F先生,我很器重他,并且他表現一直非常優秀,然而在對接華夏接口的過程中,我對F先生愛之深,責之切。當然原因不能單純的歸咎于F先生,可惡可憐的華夏接口可能才是禍害之源。

總結成果

經過一天時間的折磨,最終定位到華夏接口對于getter和setter方法書寫上有點“非人類”,請看以下代碼:

public String[] getschools() {//可惡的小寫“s”
  return schools;
 }
 public void setschools(String[] schools) {
  this.schools = schools;
 }      

經F先生路由後結果如下:

Student student = new Student();
  student.setName("lilei");
  String [] schools = new String[1];
  schools[0] = new String("21中");
  student.setschools(schools);
  String json = JSON.toJSONString(student);
  System.out.println(json);
  // {"name":"lilei"}      

那麼解決之道是什麼,大家都能想得到了。

public String[] getSchools() {
  return schools;
 }
 public void setSchools(String[] schools) {
  this.schools = schools;
 }
Student student = new Student();
  student.setName("lilei");
  String [] schools = new String[1];
  schools[0] = new String("21中");
  student.setSchools(schools);
  String json = JSON.toJSONString(student);
  System.out.println(json);
  // {"name":"lilei","schools":["21中"]}      

如果你認為你已經得到了答案,那麼請跳過以下内容,不過我認為,如果你跳過了下面章節的閱讀,你将得不償失。

事件描述

在一個安靜的傍晚,我一個人待在辦公室做華夏接口的調試工作,雖然寂寞了點,但是還是非常開心,接口調試工作很順利。然而風雲突變,華夏接口施展了一招“天狗吞日”,瞬間我就迷茫了,出現了總結成果中的第一種情況。

時間一分一秒的過去了,我本着從自我原因找起的原則,不斷審視着自己編寫的代碼,懷疑自己在對數組對象的指派上面錯誤了,接着又懷疑自己在傳遞json資料時發生錯誤。。。最終并沒有找到原因。

包大人上場

也許你看了總結成果後,感覺不就是一個大小寫問題嗎,我怎麼還喋喋不休。然而個人能力的提升,就是要反複的總結,而後才能“得道”。

1. 懷疑自己的代碼出錯了。

這永遠都是應該的,從前至後,翻看自己的代碼,看是否存在bug。發生這個資料丢失的問題後,我必須先稽核自己的代碼,看看我在對數組對象的指派時是不是有遺漏,然後看看我在使用F先生的時候是不是有問題,再看看我在調用華夏接口的時候是不是有問題。

2. 盡量不要拆東牆,補西牆。

這一點很重要,在證明自己的代碼沒有問題後,那麼接下來懷疑的對象自然就是阿裡巴巴提供的F先生,以及華夏銀行提供的API接口。那麼在這方面,我們經常容易沖動,因為好不容易抓住一下對方的把柄,我們還不樂呵一下。

我也犯錯了!在證明自己的代碼沒有問題後,我開始懷疑F先生不支援數組對象的轉換,因為F先生隻提供了JSON.parseArray、JSON.parseObject兩種方法(可笑我是多麼的片面主義),經驗主義告訴我,之前我們使用了這兩種方法分别對List、Object對象進行轉換,是沒有問題的,但是對于華夏接口使用的Object []數組,F先生是不是不支援這種寫法呢?

就如總結成功中所寫的String [] schools字段,經過我的第一步測試,發現是支援的,那麼既然支援數組,又為什麼會丢失對象呢?

我開始懷疑是不是由于資料對象的三層關系,導緻F先生無力轉換呢?

Message msg = new Message();
  Student student = new Student();
  student.setName("lilei");
  String [] schools = new String[1];
  schools[0] = new String("21中");
  student.setSchools(schools);
  msg.setParamsObject("student", student);
  String json = JSON.toJSONString(msg);
  System.out.println(json);
  // {"code":0,"parames":{"student":{"name":"lilei","schools":["21中"]}}}      

非常遺憾的是,我當時在測試這個步驟的時候,使用的是華夏提供的“非人類”的getxxx和setxxx方法(不是getXXX和setXXX)的對象,導緻我并沒有得出

{"code":0,"parames":{"student":{"name":"lilei","schools":["21中"]}}}

這個結論。

這個時候,同僚說他通過jfinal提供的JsonKit(我記得好像是這個)對象可以轉換華夏銀行提供的“非人類”的getxxx和setxxx方法的對象,我也飄飄然的認為,這必須是F先生的一個bug(當時我還和同僚一起嘲笑了阿裡巴巴也不咋地,呵呵),于是乎,他提出了使用jackjson來替換fastjson的想法,并且實作了轉換方法。

事情進展的似乎很順利,我把項目中的fastjson抛棄了,換成了jackjson的兩個jar包,并改換了對應的轉換方法。

“月有陰晴圓缺”,等我草草的把重新打包後的jar包放到伺服器上後,出現了一個驚人的錯誤,jackjson在把一個包含list的對象read為json的時候出現了錯誤(錯誤現在不記得了,等待周一的時候,我把錯誤補上),并且經曆了很長時間,我和同僚都沒有能找到原因。已經快要下班了,由于要快速的實作華夏接口的對接,我決定不能再在這個問題上花費時間了,于是乎,我決定用我的方法解決問題。

Message msg = new Message();
  Student student = new Student();
  student.setName("lilei");
  School[] schools = new School[1];
  schools[0] = new School();
  schools[0].setName("21中");
  // student.setschools(schools);
  msg.setParamsObject("student", student);
  msg.setParamsObject("list", Arrays.asList(schools));
  String json = JSON.toJSONString(msg);
  System.out.println(json);
  // {"code":0,"parames":{"list":[{"name":"21中"}],"student":{"name":"lilei"}}}
  // 注意,由于Student對象中的setschools的緣故,我需要在message對象中加入list參數,專門傳遞School數組
  Message s = JSON.parseObject(json, Message.class);
  Student ss = JSON.parseObject(s.getParamsObject("student").toString(), Student.class);
  List<School> list = JSON.parseArray(s.getParamsObject("list").toString(), School.class);
  ss.setschools(list.toArray(new School[list.size()]));
  System.out.println(ss.getschools()[0].getName());
  // 21中      

這種方式也是被華夏接口 逼迫的。

3. 翻看源碼

顯然,按照2中的方式解決了問題之後,一切就結束了嗎?顯然沒有,如果你還記得總結中說的原因,那麼接下來的工作就是找出原因。很巧合,在實際的開發過程中,我整理代碼的時候,突然發現華夏接口在進行子賬号簽約工作時,也傳遞了數組對象,并且經過F先生轉換後,資料時完全存在的,而為什麼華夏接口的清算接口在轉換過程中丢失呢?

幸好幸好,華夏接口API提供的jar包可以反編譯。經過分析,我堅定的認為,問題就發生在華夏接口提供的類中,直接告訴我,肯定是數組對象的getter和setter方法寫的有問題,經過同僚的檢視,的确,清算接口中使用了小寫的getter和setter方法(再次強調,非人類,已經無力吐槽),而子賬号簽約卻使用的大寫寫法(QNMD)。

翻看源碼無疑是解決問題的殺手锏。