feat: apt 配置文件

This commit is contained in:
yulichang 2024-07-19 18:09:24 +08:00
parent 7cd632f1ad
commit 2ee265c213
5 changed files with 244 additions and 30 deletions

View File

@ -8,25 +8,33 @@ import java.lang.annotation.Target;
/** /**
* apt注解 * apt注解
* <p> * <p>
* 默认为String.format
* <p>
* 举例
* <ul>
* <li>全大写 %S</li>
* <li>加APT后缀 %sAPT</li>
* <li>加APT前缀 APT%s</li>
* <li>加APT后缀并且大写 %SAPT</li>
* </ul>
* <p>
* 支持Ognl语法字段说明<br/> * 支持Ognl语法字段说明<br/>
* Ognl上下文 * Ognl上下文
* <ul> * <ul>
* <li>classInfo {@link com.github.yulichang.apt.OgnlRoot.ClassInfo}</li> * <li>classInfo {@link com.github.yulichang.apt.OgnlRoot.ClassInfo}</li>
* <li>stringHelper {@link com.github.yulichang.apt.OgnlRoot.StringHelper}</li> * <li>stringHelper {@link com.github.yulichang.apt.OgnlRoot.StringHelper}</li>
* </ul> * </ul>
* <p>
* 指定开头 Ognl# 这不是ognl语法这是MPJ规定的 用于区分 ognl还是String.format * 指定开头 Ognl# 这不是ognl语法这是MPJ规定的 用于区分 ognl还是String.format
* <p> * <p>
* 举例 * 举例
* <ul> * <ul>
* <li>去掉3长度的后缀并且大写 Ognl#classInfo.getClassName().substring(0, classInfo.getClassName().length() - 3).toUpperCase() </li> * <li>去掉3长度的后缀并且大写 Ognl#classInfo.className.substring(0, classInfo.className.length() - 3).toUpperCase() </li>
* <li>APT结尾 Ognl#classInfo.getClassName() + 'APT'</li> * <li>APT结尾 Ognl#classInfo.className + 'APT'</li>
* <li>全大写并且以APT结尾 Ognl#classInfo.getClassName().toUpperCase() + 'APT' </li> * <li>全大写并且以APT结尾 Ognl#classInfo.className.toUpperCase() + 'APT' </li>
* <li>"PO"结尾替换为APT且全大写 Ognl#stringHelper.replaceSuffix(classInfo.getClassName(), 'PO', 'APT').toUpperCase() </li> * <li>"PO"结尾替换为APT且全大写 Ognl#stringHelper.replaceSuffix(classInfo.className, 'PO', 'APT').toUpperCase() </li>
* </ul> * </ul>
* <p> * <p>
* 支持 三元运算 String所有方法 如lastIndexOf subString toUpperCase等 Ognl语法<p> * 支持 三元运算 String所有方法 如lastIndexOf subString toUpperCase等 Ognl语法<p>
* 若想扩展stringHelper可在github交流
* *
* @author yulichang * @author yulichang
* @since 1.5.0 * @since 1.5.0
@ -49,6 +57,18 @@ public @interface Table {
*/ */
String packageName() default "%s.apt"; String packageName() default "%s.apt";
/**
* 是否在Tables中生成对应的类字段
*/
boolean genTables() default true;
/**
* Tables中的字段名 默认大写的类名
* <p>
* 支持Ognl 默认使用String.format()
*/
String tablesPackageName() default "%s.tables";
/** /**
* Tables中的字段名 默认大写的类名 * Tables中的字段名 默认大写的类名
* <p> * <p>

View File

@ -27,11 +27,11 @@ public class OgnlRoot {
/** /**
* 类名 * 类名
*/ */
private final String className; public final String className;
/** /**
* 包名 * 包名
*/ */
private final String packageName; public final String packageName;
public ClassInfo(String className, String packageName) { public ClassInfo(String className, String packageName) {

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.github.yulichang.annotation.Table; import com.github.yulichang.annotation.Table;
import com.github.yulichang.apt.BaseColumn; import com.github.yulichang.apt.BaseColumn;
import com.github.yulichang.apt.Column; import com.github.yulichang.apt.Column;
import com.github.yulichang.processor.matedata.Conf;
import com.github.yulichang.processor.matedata.FieldInfo; import com.github.yulichang.processor.matedata.FieldInfo;
import com.github.yulichang.processor.matedata.TableInfo; import com.github.yulichang.processor.matedata.TableInfo;
import com.github.yulichang.processor.utils.StringUtil; import com.github.yulichang.processor.utils.StringUtil;
@ -13,19 +14,13 @@ import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element; import javax.lang.model.element.*;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements; import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.Diagnostic; import javax.tools.Diagnostic;
import javax.tools.JavaFileObject; import javax.tools.JavaFileObject;
import java.io.Writer; import java.io.Writer;
import java.util.Arrays; import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -38,6 +33,7 @@ public class EntityProcessor extends AbstractProcessor {
private Elements elementUtils; private Elements elementUtils;
private Types typeUtils; private Types typeUtils;
private Messager messager; private Messager messager;
private Conf globalConf;
@Override @Override
public synchronized void init(ProcessingEnvironment processingEnv) { public synchronized void init(ProcessingEnvironment processingEnv) {
@ -45,6 +41,11 @@ public class EntityProcessor extends AbstractProcessor {
this.elementUtils = processingEnv.getElementUtils(); this.elementUtils = processingEnv.getElementUtils();
this.typeUtils = processingEnv.getTypeUtils(); this.typeUtils = processingEnv.getTypeUtils();
this.messager = processingEnv.getMessager(); this.messager = processingEnv.getMessager();
this.globalConf = new Conf(processingEnv.getFiler(), this::note);
}
private void note(String msg) {
messager.printMessage(Diagnostic.Kind.NOTE, msg + " - " + UUID.randomUUID());
} }
@ -53,10 +54,12 @@ public class EntityProcessor extends AbstractProcessor {
if (!roundEnv.processingOver()) { if (!roundEnv.processingOver()) {
TypeElement table = annotations.stream().filter(i -> i.toString().equals(Table.class.getName())).findFirst().orElse(null); TypeElement table = annotations.stream().filter(i -> i.toString().equals(Table.class.getName())).findFirst().orElse(null);
if (table != null) { if (table != null) {
note("mybatis plus join processor start");
Set<? extends Element> tables = roundEnv.getElementsAnnotatedWith(table); Set<? extends Element> tables = roundEnv.getElementsAnnotatedWith(table);
tables.stream().filter(f -> f instanceof TypeElement) tables.stream().filter(f -> f instanceof TypeElement)
.map(f -> (TypeElement) f).map(this::createColumn) .map(f -> (TypeElement) f).map(this::createColumn)
.collect(Collectors.groupingBy(TableInfo::getClassPackage)) .filter(Objects::nonNull).filter(TableInfo::isGenTables)
.collect(Collectors.groupingBy(TableInfo::getTagTablesPackageName))
.forEach(this::createTables); .forEach(this::createTables);
} }
} }
@ -80,7 +83,16 @@ public class EntityProcessor extends AbstractProcessor {
* 生成Column类 * 生成Column类
*/ */
private TableInfo createColumn(TypeElement element) { private TableInfo createColumn(TypeElement element) {
TableInfo tableInfo = new TableInfo(element.getAnnotation(Table.class), element.toString(), element.getSimpleName().toString()); AnnotationMirror tb = element.getAnnotationMirrors().stream().filter(a ->
a.getAnnotationType().asElement().toString().equals(Table.class.getName())).findFirst().orElse(null);
Table table = element.getAnnotation(Table.class);
if (tb == null) {
return null;
}
Set<String> keySet = tb.getElementValues().keySet().stream().map(k ->
k.getSimpleName().toString()).collect(Collectors.toSet());
Conf conf = Conf.getConf(globalConf, table, keySet);
TableInfo tableInfo = new TableInfo(conf, element.toString(), element.getSimpleName().toString());
tableInfo.setClassPackage(elementUtils.getPackageOf(element).getQualifiedName().toString()); tableInfo.setClassPackage(elementUtils.getPackageOf(element).getQualifiedName().toString());
tableInfo.setClassComment(elementUtils.getDocComment(element)); tableInfo.setClassComment(elementUtils.getDocComment(element));
@ -127,7 +139,7 @@ public class EntityProcessor extends AbstractProcessor {
private void createTables(String tagPackage, List<TableInfo> tableInfos) { private void createTables(String tagPackage, List<TableInfo> tableInfos) {
StringBuilderHelper content = new StringBuilderHelper(); StringBuilderHelper content = new StringBuilderHelper();
// package // package
content.addPackage(tagPackage + ".tables"); content.addPackage(tagPackage);
content.newLine(); content.newLine();
// import // import
tableInfos.forEach(tableInfo -> content.addImport(tableInfo.getTagPackage() + "." + tableInfo.getTagClassName())); tableInfos.forEach(tableInfo -> content.addImport(tableInfo.getTagPackage() + "." + tableInfo.getTagClassName()));
@ -141,7 +153,7 @@ public class EntityProcessor extends AbstractProcessor {
// 添加table字段 // 添加table字段
.addTablesFields(tableInfos)); .addTablesFields(tableInfos));
writerFile(tagPackage + ".tables.Tables", content.getContent()); writerFile(tagPackage + ".Tables", content.getContent());
} }
private void writerFile(String fullClassName, String content) { private void writerFile(String fullClassName, String content) {
@ -220,7 +232,7 @@ public class EntityProcessor extends AbstractProcessor {
addComment("\t", tableInfo.getClassComment()); addComment("\t", tableInfo.getClassComment());
sb.append(String.format("\tpublic static final %s %s = new %s();\n", sb.append(String.format("\tpublic static final %s %s = new %s();\n",
tableInfo.getTagClassName(), tableInfo.getTagClassName(),
String.format(tableInfo.getTableAnnotation().tablesName(), tableInfo.getSimpleClassName()), String.format(tableInfo.getTagTablesName(), tableInfo.getSimpleClassName()),
tableInfo.getTagClassName())); tableInfo.getTagClassName()));
newLine(); newLine();
}); });

View File

@ -0,0 +1,162 @@
package com.github.yulichang.processor.matedata;
import com.github.yulichang.annotation.Table;
import javax.annotation.processing.Filer;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.Collection;
import java.util.Properties;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
public class Conf {
private String className = "%sCol";
private String packageName = "%s.apt";
private boolean genTables = true;
private String tablasPackageName = "%s.tables";
private String tablesName = "%S";
private boolean initFlag = false;
private Conf(Conf conf) {
this.className = conf.className;
this.packageName = conf.packageName;
this.genTables = conf.genTables;
this.tablasPackageName = conf.tablasPackageName;
this.tablesName = conf.tablesName;
this.initFlag = conf.initFlag;
}
public Conf(Filer filer, Consumer<String> log) {
try {
FileObject confPath = filer.createResource(StandardLocation.CLASS_OUTPUT, "", "mybatis-plus-join");
File file = new File(confPath.toUri()).getParentFile();
int loop = 0;
while (file != null && file.exists() && file.isDirectory()) {
loop++;
File[] files = file.listFiles();
if (files != null && files.length > 0) {
File confFile = Arrays.stream(files).filter(f -> f.getName().equals("mybatis-plus-join.properties")).findFirst().orElse(null);
if (confFile != null && confFile.exists()) {
log.accept(String.format("use mybatis-plus-join.properties %s", confFile.getAbsolutePath()));
this.init(confFile);
break;
}
}
file = file.getParentFile();
if (loop > 50) {
break;
}
}
if (!this.initFlag) {
log.accept("not find mybatis-plus-join.properties use default setting");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void init(File confFile) throws IOException {
this.initFlag = true;
Properties properties = new Properties();
properties.load(Files.newInputStream(confFile.toPath()));
this.className = properties.getOrDefault("className", this.className).toString();
this.packageName = properties.getOrDefault("packageName", this.packageName).toString();
this.genTables = Boolean.parseBoolean(properties.getOrDefault("genTables", Boolean.toString(this.genTables)).toString());
this.tablasPackageName = properties.getOrDefault("tablasPackageName", this.tablasPackageName).toString();
this.tablesName = properties.getOrDefault("tablesName", this.tablesName).toString();
}
public static Conf getConf(Conf globalConf, Table table, Collection<String> keys) {
if (keys == null || keys.isEmpty()) {
return globalConf;
}
Conf conf = new Conf(globalConf);
keys.forEach(key -> ConfItem.doIt(conf, key, table));
return conf;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public boolean isGenTables() {
return genTables;
}
public void setGenTables(boolean genTables) {
this.genTables = genTables;
}
public String getTablasPackageName() {
return tablasPackageName;
}
public void setTablasPackageName(String tablasPackageName) {
this.tablasPackageName = tablasPackageName;
}
public String getTablesName() {
return tablesName;
}
public void setTablesName(String tablesName) {
this.tablesName = tablesName;
}
public enum ConfItem {
className("value", Table::value, (c, v) -> c.setClassName(v.toString())),
packageName("packageName", Table::packageName, (c, v) -> c.setPackageName(v.toString())),
genTables("genTables", Table::genTables, (c, v) -> c.setGenTables((boolean) v)),
tablasPackageName("tablasPackageName", Table::tablesPackageName, (c, v) -> c.setTablasPackageName(v.toString())),
tablesName("tablesName", Table::tablesName, (c, v) -> c.setTablesName(v.toString()));
private final String action;
private final Function<Table, Object> annoVal;
private final BiConsumer<Conf, Object> doIt;
ConfItem(String action, Function<Table, Object> annoVal, BiConsumer<Conf, Object> doIt) {
this.action = action;
this.annoVal = annoVal;
this.doIt = doIt;
}
public static void doIt(Conf tableConf, String act, Table anno) {
Arrays.stream(ConfItem.values()).filter(f -> f.action.equals(act)).findFirst()
.ifPresent(item -> item.doIt.accept(tableConf, item.annoVal.apply(anno)));
}
}
@Override
public String toString() {
return "Conf{" +
"className='" + className + '\'' +
", packageName='" + packageName + '\'' +
", genTables=" + genTables +
", tablasPackageName='" + tablasPackageName + '\'' +
", tablesName='" + tablesName + '\'' +
'}';
}
}

View File

@ -1,6 +1,5 @@
package com.github.yulichang.processor.matedata; package com.github.yulichang.processor.matedata;
import com.github.yulichang.annotation.Table;
import com.github.yulichang.apt.OgnlRoot; import com.github.yulichang.apt.OgnlRoot;
import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.ognl.Ognl; import org.apache.ibatis.ognl.Ognl;
@ -27,15 +26,17 @@ public class TableInfo {
private String classPackage; private String classPackage;
private final Table tableAnnotation; private final Conf conf;
private Set<FieldInfo> fields; private Set<FieldInfo> fields;
private String tagClassName; private String tagClassName;
private String tagPackageName; private String tagPackageName;
private String tagTablesName;
private String tagTablesPackageName;
public TableInfo(Table tableAnnotation, String className, String simpleClassName) { public TableInfo(Conf conf, String className, String simpleClassName) {
this.tableAnnotation = tableAnnotation; this.conf = conf;
this.className = className; this.className = className;
this.simpleClassName = simpleClassName; this.simpleClassName = simpleClassName;
} }
@ -45,7 +46,7 @@ public class TableInfo {
*/ */
public String getTagClassName() { public String getTagClassName() {
if (tagClassName == null) { if (tagClassName == null) {
tagClassName = parse(tableAnnotation.value(), this.simpleClassName); tagClassName = parse(conf.getClassName(), this.simpleClassName);
} }
return tagClassName; return tagClassName;
} }
@ -55,11 +56,30 @@ public class TableInfo {
*/ */
public String getTagPackage() { public String getTagPackage() {
if (tagPackageName == null) { if (tagPackageName == null) {
tagPackageName = parse(tableAnnotation.packageName(), this.classPackage); tagPackageName = parse(conf.getPackageName(), this.classPackage);
} }
return tagPackageName; return tagPackageName;
} }
/**
* 获取Tables的字段名
*/
public String getTagTablesName() {
if (tagTablesName == null) {
tagTablesName = parse(conf.getTablesName(), this.simpleClassName);
}
return tagTablesName;
}
/**
* 获取Tables的路径
*/
public String getTagTablesPackageName() {
if (tagTablesPackageName == null) {
tagTablesPackageName = parse(conf.getTablasPackageName(), this.classPackage);
}
return tagTablesPackageName;
}
private String parse(String expression, String source) { private String parse(String expression, String source) {
String tag; String tag;
@ -94,7 +114,7 @@ public class TableInfo {
this.classComment = classComment; this.classComment = classComment;
} }
public String getClassPackage() { public String getClassPackage1() {
return classPackage; return classPackage;
} }
@ -102,8 +122,8 @@ public class TableInfo {
this.classPackage = classPackage; this.classPackage = classPackage;
} }
public Table getTableAnnotation() { public boolean isGenTables() {
return tableAnnotation; return this.conf.isGenTables();
} }
public Set<FieldInfo> getFields() { public Set<FieldInfo> getFields() {