问题描述
使用mybatis作为dao层的框架时,常常会使用mybatis-generator生成数据库实体类和mapper文件,这其中由于公司的项目规范,往往会在每张表里设置一些通用字段,这个时候就会用到rootClass,将这些通用的字段封装到其中,而生成的实体类自动继承rootClass定义的类,并且不会重写rootClass中已经存在的属性。
定义如下:
<javaModelGenerator targetPackage="com.gambo.guangjin.convert.dao.model" targetProject="src/main/java">
<property name="rootClass" value="com.gambo.guangjin.convert.dao.model.BaseDO"/>
<property name="suppressGeneratedAnnotations" value="true" />
</javaModelGenerator>
<sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources" />
<javaClientGenerator type="XMLMAPPER" targetPackage="com.gambo.guangjin.convert.dao.mapper" targetProject="src/main/java" />
<table tableName="convert_job"
enableCountByExample="false"
enableDeleteByExample="false"
enableSelectByExample="false"
enableUpdateByExample="false"
domainObjectName="ConvertJobDO"
mapperName="ConvertJobMapper"
/>
BaseDO的定义如下:
public class BaseDO {
private Integer id;
private Boolean deleted;
private Date createdAt;
private String createdBy;
private Date updatedAt;
private String updatedBy;
public final Integer getId() {
return id;
}
public final void setId(Integer id) {
this.id = id;
}
public final Boolean getDeleted() {
return deleted;
}
public final void setDeleted(Boolean deleted) {
this.deleted = deleted;
}
public final Date getCreatedAt() {
return createdAt;
}
public final void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public final String getCreatedBy() {
return createdBy;
}
public final void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public final Date getUpdatedAt() {
return updatedAt;
}
public final void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public final String getUpdatedBy() {
return updatedBy;
}
public final void setUpdatedBy(String updatedBy) {
this.updatedBy = updatedBy;
}
}
maven插件的定义如下:
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.2</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
<configurationFile>
${project.basedir}/src/main/resources/generatorConfig.xml
</configurationFile>
</configuration>
</plugin>
运行插件后生成的实体类,确实继承了BaseDO,但是事与愿违,其生成的属性重写了rootClass中国定义的字段,遇到这种问题无非是每次生成的实体类手动处理一下,很少有人会寻根究底,然而对于有强迫症的我很难咽的下这口气。
问题排查
生成代码的日志如下
注意这一句
[WARNING] Root class com.gambo.guangjin.convert.dao.model.BaseDO cannot be loaded, checking for member overrides is disabled for this class
也就是说rootClass定义的类并没有被加载
调试mybatis-generator-core的源码确实如此
for (ClassLoader classLoader : externalClassLoaders) {
try {
clazz = Class.forName(type, true, classLoader);
return clazz;
} catch (Exception e) {
// ignore - fail safe below
}
}
以上代码出现了classNotFoundException,这种问题一般都考虑classPath的问题,也就是说在idea中运行maven插件并不会直接加载项目默认的classPath,这个时候如果引用了项目中的class就会出现这种情况。
解决方案
我们观察到,使用mybaits-generator时需要定义数据库驱动包所在的位置:
<classPathEntry location="F:\repository\org\postgresql\postgresql\42.7.4\postgresql-42.7.4.jar" />
查询了一下官方文档 这里的classPathEntry是可以重复定义的,从而引入多个外部classPath,这里我们可以把我们项目的默认路径作为classPathEntry定义。
由于mybatis-generator的实现方案时使用class.forName反射获取rootClass中的属性,所以这里需要填写项目编译后的class路径
添加如下配置
<classPathEntry location="./target/classes" />
此时再运行插件生成的实体类则不会重写rootClass中的属性。
总结
使用编程的方式调用mybatis-generator-core的功能生成代码则不会出现上面的问题,因为在idea中运行代码的时候会先自动进行编译,生成target/class目录以及编译后的文件,并且自动加载其中的class,但是用插件的方式则需要先编译成功后在添加./target/classes的classPath到generatorConfig.xml中.