mybatis一個有意思的東西

Map<String,String> stringMap = new HashMap<>();  //1
 String value = stringMap.get("name"); //2

問個問題 如何才能讓第二行報下面的錯??

java.lang.ClassCastException: 
    java.lang.Integer cannot be cast to java.lang.String

這個問題是年前碰到的問題,今天忽然想起來了,調試了下源碼,找了找答案。
事情通過是這樣子的,有一朋友寫了相似的代碼:java

XML:
    <select id="selectAllSongInfoMap" resultType="java.util.Map">
        select * from song_Info
    </select>
 
Mapper.java:
    Map<String,String> selectAllSongInfoMap();
 
A.java:
    Map<String,String> stringMap = selectAllSongInfoMap();
    for (Map.Entry<String, String> stringStringEntry : stringMap.entrySet()) {
        String value = stringStringEntry.getValue(); //233
    }

行233報錯了:數據庫

java.lang.ClassCastException: 
    java.lang.Integer cannot be cast to java.lang.String

乍一看日誌報錯的行號是233行,這確定不能信啊,這行打死也不會報這個錯。
確定一番操做,拉線上jar包,反編譯對行號,還特麼是這行,直接蒙Bapache

時間又回到了今晚,先說結論:session

Map<String,String> myMap = null;
 Map ff = new HashMap();
 ff.put("age",22);
 myMap = ff;
 String s = myMap.get("age"); //5
 
 行5就會報錯
 java.lang.ClassCastException: 
    java.lang.Integer cannot be cast to java.lang.String
    
可是若是按照上邊寫的,你用的開發工具確定就提醒了
可是你在Mybatis中用做返回值就沒有提醒了

過程:app

  • 拉去Mybatis源碼
  • 打開源碼中的org.apache.ibatis.session.SqlSessionTest類
  • 測試類配好數據庫直接跑
  • 跟蹤代碼直到要把數據庫查出的值轉換成咱們指定的類型的時候
  • org.apache.ibatis.executor.resultset.DefaultResultSetHandler#getRowValue(org.apache.ibatis.executor.resultset.ResultSetWrapper, org.apache.ibatis.mapping.ResultMap, java.lang.String)
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
    final ResultLoaderMap lazyLoader = new ResultLoaderMap();
    //根據xml中指定的返回值建立對象 
    //這裏java.util.Map 就會被實力化爲 new HashMap() 沒有指定範型
    Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
    if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
        // 這裏就厲害了 根據rowValue實例化  先看後邊的
      final MetaObject metaObject = configuration.newMetaObject(rowValue);
      boolean foundValues = this.useConstructorMappings;
       //到這裏 也就是說 
        //MetaObject 被實例化成功
        //其中的 objectWrapper 則被實例化成了 MapWrapper
        //MapWrapper 中有個 Map<String, Object> map 屬性
        //rowValue 則被賦值給了 map
        //而 map 則能夠做爲 rowValue 的引用胡做非爲
        
        //後邊 兩個賦值操做 
      if (shouldApplyAutomaticMappings(resultMap, false)) {
        foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
      }
      foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
      foundValues = lazyLoader.size() > 0 || foundValues;
      rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
    }
    return rowValue;
  }
  
  //實例化 MetaObject
  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;
    this.reflectorFactory = reflectorFactory;

    //各式各樣
    if (object instanceof ObjectWrapper) {
      this.objectWrapper = (ObjectWrapper) object;
    } else if (objectWrapperFactory.hasWrapperFor(object)) {
      this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    } else if (object instanceof Map) {
    
        //咱們的Map 確定就走這裏了
      this.objectWrapper = new MapWrapper(this, (Map) object);
    } else if (object instanceof Collection) {
      this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    } else {
      this.objectWrapper = new BeanWrapper(this, object);
    }
  }
  
  public class MapWrapper extends BaseWrapper {

        //原來裏面是有範型
      private final Map<String, Object> map;
    
      public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
        super(metaObject);
        this.map = map;
      }
      
      .
      .
      .
      
  }

大體再一梳理,就是這麼回事,數據庫的字段有int類型因此報了轉換的錯:工具

Map<String,String> myMap = null; //myMap
        
    Map ff = new HashMap();  // ff
    Map<String,Object> mObject = ff;  // mObject
    mObject.put("c",2);
    mObject.put("a","b");
        
    myMap = ff;
    String s = myMap.get("c"); //報錯一行

mObject仗着本身有 ff 的引用,胡亂塞值,等到真正的使用者myMap使用的時候確報了強制轉換的錯誤。開發工具

忽然聯想到昨晚看的奇葩說辯論「扶弟魔」,女人揹着老公把錢借給弟弟,結果老公想買東西的時候發現沒錢了。測試

本文由博客一文多發平臺 OpenWrite 發佈!this

相關文章
相關標籤/搜索