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

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.github.yulichang.annotation.Table;
import com.github.yulichang.apt.BaseColumn;
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.TableInfo;
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.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.*;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.Writer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@ -38,6 +33,7 @@ public class EntityProcessor extends AbstractProcessor {
private Elements elementUtils;
private Types typeUtils;
private Messager messager;
private Conf globalConf;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
@ -45,6 +41,11 @@ public class EntityProcessor extends AbstractProcessor {
this.elementUtils = processingEnv.getElementUtils();
this.typeUtils = processingEnv.getTypeUtils();
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()) {
TypeElement table = annotations.stream().filter(i -> i.toString().equals(Table.class.getName())).findFirst().orElse(null);
if (table != null) {
note("mybatis plus join processor start");
Set<? extends Element> tables = roundEnv.getElementsAnnotatedWith(table);
tables.stream().filter(f -> f instanceof TypeElement)
.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);
}
}
@ -80,7 +83,16 @@ public class EntityProcessor extends AbstractProcessor {
* 生成Column类
*/
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.setClassComment(elementUtils.getDocComment(element));
@ -127,7 +139,7 @@ public class EntityProcessor extends AbstractProcessor {
private void createTables(String tagPackage, List<TableInfo> tableInfos) {
StringBuilderHelper content = new StringBuilderHelper();
// package
content.addPackage(tagPackage + ".tables");
content.addPackage(tagPackage);
content.newLine();
// import
tableInfos.forEach(tableInfo -> content.addImport(tableInfo.getTagPackage() + "." + tableInfo.getTagClassName()));
@ -141,7 +153,7 @@ public class EntityProcessor extends AbstractProcessor {
// 添加table字段
.addTablesFields(tableInfos));
writerFile(tagPackage + ".tables.Tables", content.getContent());
writerFile(tagPackage + ".Tables", content.getContent());
}
private void writerFile(String fullClassName, String content) {
@ -220,7 +232,7 @@ public class EntityProcessor extends AbstractProcessor {
addComment("\t", tableInfo.getClassComment());
sb.append(String.format("\tpublic static final %s %s = new %s();\n",
tableInfo.getTagClassName(),
String.format(tableInfo.getTableAnnotation().tablesName(), tableInfo.getSimpleClassName()),
String.format(tableInfo.getTagTablesName(), tableInfo.getSimpleClassName()),
tableInfo.getTagClassName()));
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;
import com.github.yulichang.annotation.Table;
import com.github.yulichang.apt.OgnlRoot;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.ognl.Ognl;
@ -27,15 +26,17 @@ public class TableInfo {
private String classPackage;
private final Table tableAnnotation;
private final Conf conf;
private Set<FieldInfo> fields;
private String tagClassName;
private String tagPackageName;
private String tagTablesName;
private String tagTablesPackageName;
public TableInfo(Table tableAnnotation, String className, String simpleClassName) {
this.tableAnnotation = tableAnnotation;
public TableInfo(Conf conf, String className, String simpleClassName) {
this.conf = conf;
this.className = className;
this.simpleClassName = simpleClassName;
}
@ -45,7 +46,7 @@ public class TableInfo {
*/
public String getTagClassName() {
if (tagClassName == null) {
tagClassName = parse(tableAnnotation.value(), this.simpleClassName);
tagClassName = parse(conf.getClassName(), this.simpleClassName);
}
return tagClassName;
}
@ -55,11 +56,30 @@ public class TableInfo {
*/
public String getTagPackage() {
if (tagPackageName == null) {
tagPackageName = parse(tableAnnotation.packageName(), this.classPackage);
tagPackageName = parse(conf.getPackageName(), this.classPackage);
}
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) {
String tag;
@ -94,7 +114,7 @@ public class TableInfo {
this.classComment = classComment;
}
public String getClassPackage() {
public String getClassPackage1() {
return classPackage;
}
@ -102,8 +122,8 @@ public class TableInfo {
this.classPackage = classPackage;
}
public Table getTableAnnotation() {
return tableAnnotation;
public boolean isGenTables() {
return this.conf.isGenTables();
}
public Set<FieldInfo> getFields() {