写了一个mybatis的mapper映射文件,其中java bean定义如下:
public class GroupCourseResult extends GroupResult {
private String cid;
private String cname;
public GroupCourseResult(int stuschool, int nian, String stuclass, String cid, String cname) {
super(stuschool, nian, stuclass);
this.cid = cid;
this.cname = cname;
}
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
部分mybatis映射文件如下:
<select id="selectFailedCourseRationByGroupIdAndCourseName" resultType="GroupCourseResult">
...
</select>
实体类中的属性名和查询的列名完全匹配,但是没有查询stuclass,则封装后的实体类中的stuclass属性应该为空。
然而程序运行后,stuclass属性不仅不为空,还与cname完全相同,百思不得其解,故翻了翻mybatis的源码。
在mybatis中的DefaultResultSetHandler类中,createResultObject方法的代码如下:
private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
throws SQLException {
final Class<?> resultType = resultMap.getType();
final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
if (hasTypeHandlerForResultObject(rsw, resultType)) {
return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
} else if (!constructorMappings.isEmpty()) {
return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
return objectFactory.create(resultType);
} else if (shouldApplyAutomaticMappings(resultMap, false)) {
return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
}
throw new ExecutorException("Do not know how to create an instance of " + resultType);
}
经过调试发现,mybatis会先查找该javabean有无默认构造方法,如果有则采用设值注入,若没有,则根据javabean的有参构造方法进行设值,而在8以前的jdk版本中,我们利用反射只能获取到参数类型,不能获取到参数名称,这其中设值可能出现了匹配失误,将cname的值同时赋给了cname和stuclass。想要解决这个问题,只须在javabean中添加默认构造方法即可。