前言: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)。
翻看源码无疑是解决问题的杀手锏。