feat: 支持在APT中通过表达式选择package层级

This commit is contained in:
ZhengJin 2024-08-21 15:50:43 +08:00
parent cb6b0fb1d4
commit f852491dfd
No known key found for this signature in database
5 changed files with 73 additions and 8 deletions

View File

@ -26,16 +26,35 @@ MyBatis-Flex 使用了 APTAnnotation Processing Tool技术在项目编
| processor.mapper.annotation | 开启 @Mapper 注解 | true/false | false | | processor.mapper.annotation | 开启 @Mapper 注解 | true/false | false |
| processor.mapper.baseClass | 自定义 Mapper 的父类 | 全路径类名 | com.mybatisflex.core.BaseMapper | | processor.mapper.baseClass | 自定义 Mapper 的父类 | 全路径类名 | com.mybatisflex.core.BaseMapper |
| processor.mapper.package | 自定义 Mapper 生成的包名 | 合法的包名 | ${entityPackage}.mapper | | processor.mapper.package | 自定义 Mapper 生成的包名 | 合法的包名 | ${entityPackage}.mapper |
| processor.tableDef.package | 生成辅助类的包名 | 合法的包名 | ${entityPackage}.table |
| processor.tableDef.propertiesNameStyle | 生成辅助类的字段风格 | upperCase, lowerCase<br />upperCamelCase, lowerCamelCase | upperCase | | processor.tableDef.propertiesNameStyle | 生成辅助类的字段风格 | upperCase, lowerCase<br />upperCamelCase, lowerCamelCase | upperCase |
| processor.tableDef.instanceSuffix | 生成的表对应的变量后缀 | string | 空字符串 | | processor.tableDef.instanceSuffix | 生成的表对应的变量后缀 | string | 空字符串 |
| processor.tableDef.classSuffix | 生成的 TableDef 类的后缀 | string | TableDef | | processor.tableDef.classSuffix | 生成的 TableDef 类的后缀 | string | TableDef |
| processor.tableDef.ignoreEntitySuffixes | 过滤 Entity 后缀 | string | - | | processor.tableDef.ignoreEntitySuffixes | 过滤 Entity 后缀 | string | - |
对于示例中的包名表达式,说明如下:
1. 仅支持以下配置项使用表达式
```text
processor.allInTables.package
processor.mapper.package
processor.tableDef.package
```
2. `${entityPackage}`: 表示 Entity 类所在的包名
3. `${entityPackage.parent}`: 表示 Entity 类所在的上一级包名
4. `parent` 参数的数量没有限制,但如果超出了可能的层级,则会导致异常
**示例配置:** **示例配置:**
假设 Example 类的全限定类名为 `com.mybatisflex.entity.Example` 假设 Example 类的全限定类名为 `com.mybatisflex.entity.Example`
配置内容如下:
```properties
processor.allInTables.package=${entityPackage}.table
processor.mapper.package=${entityPackage.parent}.mapper
processor.tableDef.package=${entityPackage.parent.parent}.table
```
生成类的全限定类名如下: 生成类的全限定类名如下:

View File

@ -125,6 +125,7 @@ public class MybatisFlexProcessor extends AbstractProcessor {
String mapperBaseClass = configuration.get(ConfigurationKey.MAPPER_BASE_CLASS); String mapperBaseClass = configuration.get(ConfigurationKey.MAPPER_BASE_CLASS);
// tableDef 配置 // tableDef 配置
String tableDefPackage = configuration.get(ConfigurationKey.TABLE_DEF_PACKAGE);
String tableDefClassSuffix = configuration.get(ConfigurationKey.TABLE_DEF_CLASS_SUFFIX); String tableDefClassSuffix = configuration.get(ConfigurationKey.TABLE_DEF_CLASS_SUFFIX);
String tableDefInstanceSuffix = configuration.get(ConfigurationKey.TABLE_DEF_INSTANCE_SUFFIX); String tableDefInstanceSuffix = configuration.get(ConfigurationKey.TABLE_DEF_INSTANCE_SUFFIX);
String tableDefPropertiesNameStyle = configuration.get(ConfigurationKey.TABLE_DEF_PROPERTIES_NAME_STYLE); String tableDefPropertiesNameStyle = configuration.get(ConfigurationKey.TABLE_DEF_PROPERTIES_NAME_STYLE);
@ -180,23 +181,23 @@ public class MybatisFlexProcessor extends AbstractProcessor {
tableInfo.setEntityComment(elementUtils.getDocComment(entityClassElement)); tableInfo.setEntityComment(elementUtils.getDocComment(entityClassElement));
// 生成 TableDef 文件 // 生成 TableDef 文件
String tableDefPackage = StrUtil.buildTableDefPackage(entityClass); String realTableDefPackage = StrUtil.isBlank(tableDefPackage) ? StrUtil.buildTableDefPackage(entityClass) : StrUtil.processPackageExpression(entityClass, tableDefPackage);
String tableDefClassName = entityClassName.concat(tableDefClassSuffix); String tableDefClassName = entityClassName.concat(tableDefClassSuffix);
String tableDefContent = ContentBuilder.buildTableDef(tableInfo, allInTablesEnable, tableDefPackage, tableDefClassName String tableDefContent = ContentBuilder.buildTableDef(tableInfo, allInTablesEnable, realTableDefPackage, tableDefClassName
, tableDefPropertiesNameStyle, tableDefInstanceSuffix, columnInfos, defaultColumns); , tableDefPropertiesNameStyle, tableDefInstanceSuffix, columnInfos, defaultColumns);
// 将文件所依赖的 Element 传入 Filer 表示此 TableDef 依赖这个类以保证增量编译时不丢失内容 // 将文件所依赖的 Element 传入 Filer 表示此 TableDef 依赖这个类以保证增量编译时不丢失内容
processGenClass(genPath, tableDefPackage, tableDefClassName, tableDefContent, entityClassElement); processGenClass(genPath, realTableDefPackage, tableDefClassName, tableDefContent, entityClassElement);
if (allInTablesEnable) { if (allInTablesEnable) {
// 标记 entity 如果没有配置 Tables 生成位置 entity 位置为准 // 标记 entity 如果没有配置 Tables 生成位置 entity 位置为准
entityClassReference = entityClass; entityClassReference = entityClass;
// 构建 Tables 常量属性及其导包 // 构建 Tables 常量属性及其导包
ContentBuilder.buildTablesField(importBuilder, fieldBuilder, tableInfo, tableDefClassSuffix, tableDefPropertiesNameStyle, tableDefInstanceSuffix); ContentBuilder.buildTablesField(importBuilder, fieldBuilder, tableInfo, tableDefClassSuffix, tableDefPropertiesNameStyle, tableDefInstanceSuffix, realTableDefPackage);
} }
// 是否生成 Mapper 文件 // 是否生成 Mapper 文件
if ("true".equalsIgnoreCase(mapperGenerateEnable) && table.mapperGenerateEnable()) { if ("true".equalsIgnoreCase(mapperGenerateEnable) && table.mapperGenerateEnable()) {
String realMapperPackage = StrUtil.isBlank(mapperPackage) ? StrUtil.buildMapperPackage(entityClass) : mapperPackage; String realMapperPackage = StrUtil.isBlank(mapperPackage) ? StrUtil.buildMapperPackage(entityClass) : StrUtil.processPackageExpression(entityClass, mapperPackage);
String mapperClassName = entityClassName.concat("Mapper"); String mapperClassName = entityClassName.concat("Mapper");
boolean mapperAnnotationEnable = "true".equalsIgnoreCase(mapperAnnotation); boolean mapperAnnotationEnable = "true".equalsIgnoreCase(mapperAnnotation);
String mapperClassContent = ContentBuilder.buildMapper(tableInfo, realMapperPackage, mapperClassName, mapperBaseClass, mapperAnnotationEnable); String mapperClassContent = ContentBuilder.buildMapper(tableInfo, realMapperPackage, mapperClassName, mapperBaseClass, mapperAnnotationEnable);
@ -207,7 +208,7 @@ public class MybatisFlexProcessor extends AbstractProcessor {
// 确定了要生成 Tables 且拥有至少一个被 Table 注解的类时再生成 Tables // 确定了要生成 Tables 且拥有至少一个被 Table 注解的类时再生成 Tables
if (allInTablesEnable && entityClassReference != null) { if (allInTablesEnable && entityClassReference != null) {
// 生成 Tables 文件 // 生成 Tables 文件
String realTablesPackage = StrUtil.isBlank(allInTablesPackage) ? StrUtil.buildTableDefPackage(entityClassReference) : allInTablesPackage; String realTablesPackage = StrUtil.isBlank(allInTablesPackage) ? StrUtil.buildTableDefPackage(entityClassReference) : StrUtil.processPackageExpression(entityClassReference, allInTablesPackage);
String realTablesClassName = StrUtil.isBlank(allInTablesClassName) ? "Tables" : allInTablesClassName; String realTablesClassName = StrUtil.isBlank(allInTablesClassName) ? "Tables" : allInTablesClassName;
String tablesContent = ContentBuilder.buildTables(importBuilder, fieldBuilder, realTablesPackage, allInTablesClassName); String tablesContent = ContentBuilder.buildTables(importBuilder, fieldBuilder, realTablesPackage, allInTablesClassName);
processGenClass(genPath, realTablesPackage, realTablesClassName, tablesContent, elementsAnnotatedWith.toArray(new Element[0])); processGenClass(genPath, realTablesPackage, realTablesClassName, tablesContent, elementsAnnotatedWith.toArray(new Element[0]));

View File

@ -168,8 +168,7 @@ public class ContentBuilder {
* 构建 Tables 文件常量属性 * 构建 Tables 文件常量属性
*/ */
public static void buildTablesField(StringBuilder importBuilder, StringBuilder fieldBuilder, TableInfo tableInfo, public static void buildTablesField(StringBuilder importBuilder, StringBuilder fieldBuilder, TableInfo tableInfo,
String tableDefClassSuffix, String tableDefPropertiesNameStyle, String tableDefInstanceSuffix) { String tableDefClassSuffix, String tableDefPropertiesNameStyle, String tableDefInstanceSuffix, String tableDefPackage) {
String tableDefPackage = StrUtil.buildTableDefPackage(tableInfo.getEntityName());
String tableDefClassName = tableInfo.getEntitySimpleName().concat(tableDefClassSuffix); String tableDefClassName = tableInfo.getEntitySimpleName().concat(tableDefClassSuffix);
importBuilder.append("import ").append(tableDefPackage).append('.').append(tableDefClassName).append(";\n"); importBuilder.append("import ").append(tableDefPackage).append('.').append(tableDefClassName).append(";\n");
String entityComment = tableInfo.getEntityComment(); String entityComment = tableInfo.getEntityComment();

View File

@ -77,6 +77,11 @@ public enum ConfigurationKey {
MAPPER_PACKAGE("processor.mapper.package", null), MAPPER_PACKAGE("processor.mapper.package", null),
/**
* 自定义 Class 生成的包名
*/
TABLE_DEF_PACKAGE("processor.tableDef.package", null),
/** /**
* 生成的 Class 的后缀 * 生成的 Class 的后缀
*/ */

View File

@ -16,6 +16,11 @@
package com.mybatisflex.processor.util; package com.mybatisflex.processor.util;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/** /**
* 字符串工具类 * 字符串工具类
* *
@ -28,6 +33,8 @@ public class StrUtil {
private StrUtil() { private StrUtil() {
} }
private static final Pattern PACKAGE_REGEX = Pattern.compile("(?<expression>\\$\\{entityPackage[.parent]*\\})(?<subPackage>.*)");
/** /**
* com.mybatisflex.test.entity.Account -> Account * com.mybatisflex.test.entity.Account -> Account
*/ */
@ -114,6 +121,40 @@ public class StrUtil {
} }
} }
/**
* 解析包名表达式
* <p>{@code `${entityPackage}`}替换为实际实体包名, 表达式中如果存在一个{@code `.parent`}则缩减包名末尾的一位</p>
* <p>示例{@code `entityClass = com.test1.test2`}<br>
* 1. 对于{@code `packageStr = ${entityPackage}`}处理结果为 {@code `com.test1.test2`}<br>
* 2. 对于{@code `packageStr = ${entityPackage.parent}`}处理结果为 {@code `com.test1`}<br>
* 3. 对于{@code `packageStr = ${entityPackage.parent}.customize`}处理结果为 {@code `com.test1.customize`}
* </p>
*/
public static String processPackageExpression(String entityClass, String packageStr) {
String entityPackage = entityClass.substring(0, entityClass.lastIndexOf("."));
Matcher matcher = PACKAGE_REGEX.matcher(packageStr);
if (!matcher.find()) {
return packageStr;
}
String expression = matcher.group("expression");
expression = expression.substring(2, expression.length() - 1);
String subPackage = matcher.group("subPackage");
List<String> entityPackageSplit = Arrays.asList(entityPackage.split("\\."));
while (expression.contains(".parent")) {
if (entityPackageSplit.size() == 0) {
throw new RuntimeException("Expression [.parent] has exceeded the maximum limit.");
}
int index = expression.lastIndexOf(".parent");
if (index != -1) {
expression = expression.substring(0, index);
entityPackageSplit = entityPackageSplit.subList(0, entityPackageSplit.size() - 1);
}
}
expression = expression.replace("entityPackage", String.join(".", entityPackageSplit));
return expression + subPackage;
}
public static boolean isGetterMethod(String methodName, String property) { public static boolean isGetterMethod(String methodName, String property) {
if (methodName.startsWith("get") && methodName.length() > 3) { if (methodName.startsWith("get") && methodName.length() > 3) {
return firstCharToUpperCase(property).concat("()").equals(methodName.substring(3)); return firstCharToUpperCase(property).concat("()").equals(methodName.substring(3));