记录一种Mybatis的奇怪状况

最近在帮人调试代码的时候,发现了这样一个问题:java

工程是Spring Boot + Mybatis,主要代码以下:sql

xxxMapper.xml:mybatis

<resultMap id = "BaseResultMap" type = "aaa.bbb.ccc.xxxVo">
  <id column="id" jdbcType="Integer" property="id" />
  ...
</resultMap>

<select id="selectSomething" resultMap="BaseResultMap">
  select 
    id, xxx ...
  from
  where
</select>

xxxMapper.java:app

package ...

import ...

public interface xxxMapper {
  List<yyyVo> selectSomething();
  
  ...
}

xxxServiceImpl.java:ide

package ...

import ...

@Serivce
public class xxxSerivceImpl implements xxxService {

  @Autowired
  private xxxMapper xxxDao;

  @Override
  Result selectSomething(){
    ...
    List<yyyVo> list = xxxDao.selectSomething();

    foreach(yyyVo yyy : list){
        yyy.getSth();
    }
  }
  
  ...
}

你们应该已经发现了:SQL的返回值在xxxMapper.xml中被定义为xxxVo,可是在xxxMapper.java之中却被定义为List<yyyVo>,而且在后面的service层使用该方法时,也把返回结果看成List<yyyVo>来操做。但奇怪的是,当sql执行结束并把结果赋值给List<yyyVo>时,并无报错,只有当for循环中取list的每一项的值的时候,才会抛出class cast Exception。调试

这个状况有点奇怪,主要缘由是Java在处理泛型的时候进行了类型擦除。编译器关注的只有xxxServiceImpl中的code

List<yyyVo> list = xxxDao.selectSomething();

对于编译器而言,这一个赋值语句的左右两端都是List<yyyVo>,因此能够正常编译经过。xml中对sql返回的数据类型定义为xxxVo的状况根本不被编译器探测到。在执行代码时,因为泛型内部的类型是擦除的。因此mybatis把返回的数据组成List<xxxVo>赋值给list的时候,由于双方都是List<>,也能正常执行。只有当程序从list中取出数据时,由于代码中认为list的每一个数据都应该是yyyVo,而实际的list时xxxVo,所以产生了class cast Exception。xml

相关文章
相关标签/搜索