前言
笔者所在的公司使用的是一款自研的类似hibernate的orm框架,该框架在处理insert时是通过反射调用对象的get方法获取到要插入的字段值,并且最终拼接成完整的sql来插入到数据库。
发现问题
之前写代码都是以下这种写法来进行插入的:
Student student = new Student();
student.setAge(18);
student.setHome("shanghai");
student.setName("cz");
getDao(StudentDao.class).insert(student);
后来一次提供对外接口,为了偷懒,于是把要入库set的值都做为接口入参,入参字段也保持和对象的变量名保持一致,然后通过反序列的方式构造出一个对象,然后调用insert方法来入库。样例代码如下:
String json = "{"name":"cz","age":18}"; // 由接口调用方传入
Gson gson = new Gson();
Student student = gson.fromJson(json, Student.class);
student.setHome("bejing"); // 这里为了凸显效果,手动调用set方法设置一个值
getDao(StudentDao.class).insert(student);
但是当测试代码的时候发现打印出的sql如下: insert into student(home) values('beijing'); 理论上正常的sql应该是如下: insert into student(name, age, home) values('cz', 18, 'beijing');
问题原因:
开始我怀疑是反序列化后的对象为空导致的,debug了下,发现确实是有值的,那么原因是什么呢,多次debug框架代码发现框架实现inert的原理是将调用set方法传入的值保存到了一个集合中,而拼接sql是根据这个新的对象中的字段和值就是根据这个集合来的。那么最大的原因可能就是set方法没有被调用,于是抱着实验的心态,做了一个简单的试验:
- 第一步:将Student对象中的set方法全部删除
- 第二步:使用gson.fromJson(json, Student.class);方法来反序列化对象。
- 第三步:调用Student的getXxx()方法来获取值
结论:所有的get方法都获取到了值。说明Gson反序列化对象并不是通过反射调用set方法来给对象赋值的。
于是我又按照上述实验过程测试了FastJson框架,然而结果却和gson的实验结果大相径庭,调用对象的getXxx()方法获取到的全部为空,于是又在对象的set方法中添加了System.out.print()方法,最终打印出了我想要的内容。
结论:fastJson是通过反射调用set方法来给对象赋值的。
问题解决:
知道了问题的原因,那解决方法就很明了了,我这里是通过使用FastJson代替Gson来解决的。