Mybatis使用typealias要注意类冲突的问题

mybatis中可以使用typeAlias指定一个类起一个可以理解或者方便记忆的别名,这个别名可以用来放在xml配置文件中。

使用方法有两种,一种是指定一个具体的类的别名,另一种是指定一个包中的所有的类。

<typeAliases>
 <!--  指定一个具体的类的别名 -->
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
 <!--  指定一个包中所有类的别名,后面会讲到mybatis是如何注册这个包里的类 -->
  <package name="domain.blog"/>
</typeAliases>

首先我们看下第一种方法源代码是如何实现

public void registerAlias(String alias, Class value) {    
    assert alias != null;   
    // 把别名转为小写字母
    String key = alias.toLowerCase();   
    // 如果key或者alias如果已经添加到了map中,且对应的class和已添加的不一致则抛出异常
    if (TYPE_ALIASES.containsKey(key) && !TYPE_ALIASES.get(key).equals(value.getName()) && TYPE_ALIASES.get(alias) != null) {      
        if (!value.equals(TYPE_ALIASES.get(alias))) {        
            throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(alias).getName() + "'.");
      }
    }    
    // 否则添加到map中    
    TYPE_ALIASES.put(key, value);
  }

请注意下这个结果集的结构是

private final HashMap<String, Class> TYPE_ALIASES = new HashMap<String, Class>();

接下来我们看下第二种使用方法的源代码

public void registerAliases(String packageName){    
    // 第二个会在mybatis的io去寻找对应的类时会用到    
    // 因为是把这个包中所有的类都进行别名注册,因而用的的Object类
    registerAliases(packageName, Object.class);
}  

public void registerAliases(String packageName, Class superType){
    ResolverUtil<Class> resolverUtil = new ResolverUtil<Class>();    
    // mybatis的io去包中寻找对应的类,因为是把这个包中所有的类都进行别名注册    
    // 因而此时会将所有的类都读到
    resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
    Set<Class<? extends Class>> typeSet = resolverUtil.getClasses();    
    for(Class type : typeSet){      
        //Ignore inner classes and interfaces (including package-info.java)     
        // 忽略内部类和接口
        if (!type.isAnonymousClass() && !type.isInterface()) {
          registerAlias(type);
        }
    }
  }
  
 public void registerAlias(Class type) {    
    // 利用反射机制得到这个类的不包含包名的简单名称
    String alias = type.getSimpleName();    
    // 如果这个类有Alias这个注解,获取这个注解的值作为别名,否则就用自己的原始类名
    Alias aliasAnnotation = (Alias) type.getAnnotation(Alias.class);    
    if (aliasAnnotation != null) {
      alias = aliasAnnotation.value();
    } 
    // 开始注册,这个步骤使用的是第一种方法
    registerAlias(alias, type);
  }


那么请注意上面这个方法,取一个类的simplename,仅仅是取类名哦!

String alias = type.getSimpleName();


这个就是我今天遇到的一个坑,

<typeAliases>
   <package name="com.xxx.xxx.thirdparty" />
</typeAliases>

这个类中有两个同名类ConstUtils,那么一个类在放到别名map后,另一个同名类采用的是getsimplename()后也会尝试放到TYPE_ALIAS,于是就报下面的错误了。

The alias 'ConstUtils' is already mapped to the value 'xxx'.

// 如果key或者alias如果已经添加到了map中,且对应的class和已添加的不一致则抛出异常
    if (TYPE_ALIASES.containsKey(key) && !TYPE_ALIASES.get(key).equals(value.getName()) && TYPE_ALIASES.get(alias) != null) {      
        if (!value.equals(TYPE_ALIASES.get(alias))) {        
            throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(alias).getName() + "'.");
      }
    }


解决方案很简单,采用第一种别名注册方法,或者改变下同名类,不要在同一个别名包注册路径下出现。

参考文档:https://github.com/mybatis/mybatis-3/issues/6


你可能感兴趣的:(Mybatis使用typealias要注意类冲突的问题)