feat: apt ognl

This commit is contained in:
yulichang 2024-07-17 02:55:03 +08:00
parent 30377e4f5e
commit 7cd632f1ad
4 changed files with 183 additions and 53 deletions

View File

@ -1,37 +1,59 @@
package com.github.yulichang.annotation;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
/**
* apt注解
* <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>
* </ul>
* <p>
* 支持 三元运算 String所有方法 如lastIndexOf subString toUpperCase等 Ognl语法<p>
* 若想扩展stringHelper可在github交流
*
* @author yulichang
* @since 1.5.0
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Table {
/**
* 生成类的类名前缀
* APT类名
* <p>
* 支持Ognl 默认使用String.format()
*/
String prefix() default "";
/**
* 生成类的类名后缀
*/
String suffix() default "";
/**
* format 优先级低如果配置了prefix或suffix则不会生效
*/
String format() default "%sCol";
String value() default "%sCol";
/**
* 生成类的包名
* <p>
* 支持Ognl 默认使用String.format()
*/
String packageName() default "apt";
String packageName() default "%s.apt";
/**
* Tables中的字段名 默认大写的类名
* <p>
* 支持Ognl 默认使用String.format()
*/
String tablesName() default "%S";
}
}

View File

@ -0,0 +1,83 @@
package com.github.yulichang.apt;
import lombok.Getter;
import java.util.Objects;
/**
* apt ognl表达式上下文
*
* @author yulichang
* @since 1.5.0
*/
@Getter
public class OgnlRoot {
private final ClassInfo classInfo;
private final StringHelper stringHelper;
public OgnlRoot(String className, String packageName) {
this.classInfo = new ClassInfo(className, packageName);
this.stringHelper = new StringHelper();
}
@Getter
public static class ClassInfo {
/**
* 类名
*/
private final String className;
/**
* 包名
*/
private final String packageName;
public ClassInfo(String className, String packageName) {
this.className = className;
this.packageName = packageName;
}
}
@SuppressWarnings("unused")
public static final class StringHelper {
/**
* 替换后缀
*
* @param str 原字符串
* @param suffix 指定后缀
* @param replacement 新后缀
*/
public String replaceSuffix(String str, String suffix, String replacement) {
if (isBlank(str)) {
return str;
}
String rep = Objects.isNull(replacement) ? "" : replacement;
if (isBlank(suffix)) {
return str + rep;
}
if (str.endsWith(suffix)) {
return str.substring(0, str.length() - suffix.length()) + rep;
}
return str;
}
/**
* 获取上级包名
*
* @param pk 报名
* @return 上级报名
*/
public String getParentPackage(String pk) {
if (pk.lastIndexOf(".") > -1) {
return pk;
}
return pk.substring(0, pk.lastIndexOf('.'));
}
private boolean isBlank(String str) {
return str == null || str.trim().isEmpty();
}
}
}

View File

@ -9,9 +9,11 @@ import com.github.yulichang.processor.matedata.TableInfo;
import com.github.yulichang.processor.utils.StringUtil;
import javax.annotation.processing.AbstractProcessor;
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;
@ -35,21 +37,28 @@ public class EntityProcessor extends AbstractProcessor {
private Elements elementUtils;
private Types typeUtils;
private Messager messager;
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.elementUtils = processingEnv.getElementUtils();
this.typeUtils = processingEnv.getTypeUtils();
this.messager = processingEnv.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (!roundEnv.processingOver()) {
roundEnv.getElementsAnnotatedWith(Table.class).stream().filter(f -> f instanceof TypeElement)
.map(f -> (TypeElement) f).map(this::createColumn)
.collect(Collectors.groupingBy(TableInfo::getClassPackage))
.forEach(this::createTables);
TypeElement table = annotations.stream().filter(i -> i.toString().equals(Table.class.getName())).findFirst().orElse(null);
if (table != null) {
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))
.forEach(this::createTables);
}
}
return false;
}
@ -71,9 +80,7 @@ public class EntityProcessor extends AbstractProcessor {
* 生成Column类
*/
private TableInfo createColumn(TypeElement element) {
TableInfo tableInfo = new TableInfo(element.getAnnotation(Table.class));
tableInfo.setClassName(element.toString());
tableInfo.setSimpleClassName(element.getSimpleName().toString());
TableInfo tableInfo = new TableInfo(element.getAnnotation(Table.class), element.toString(), element.getSimpleName().toString());
tableInfo.setClassPackage(elementUtils.getPackageOf(element).getQualifiedName().toString());
tableInfo.setClassComment(elementUtils.getDocComment(element));
@ -146,7 +153,7 @@ public class EntityProcessor extends AbstractProcessor {
writer.flush();
writer.close();
} catch (Exception e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
this.messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage());
}
}

View File

@ -1,7 +1,11 @@
package com.github.yulichang.processor.matedata;
import com.github.yulichang.annotation.Table;
import com.github.yulichang.processor.utils.StringUtil;
import com.github.yulichang.apt.OgnlRoot;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlContext;
import org.apache.ibatis.ognl.OgnlException;
import java.util.Set;
@ -12,58 +16,76 @@ import java.util.Set;
@SuppressWarnings("unused")
public class TableInfo {
public TableInfo(Table tableAnnotation) {
this.tableAnnotation = tableAnnotation;
}
public static final String OGNL_PREFIX = "OGNL#";
private String className;
private String simpleClassName;
private final String className;
private final String simpleClassName;
private String classComment;
private String classPackage;
private Table tableAnnotation;
private final Table tableAnnotation;
private Set<FieldInfo> fields;
private String tagClassName;
private String tagPackageName;
public TableInfo(Table tableAnnotation, String className, String simpleClassName) {
this.tableAnnotation = tableAnnotation;
this.className = className;
this.simpleClassName = simpleClassName;
}
/**
* 生成的类名
*/
public String getTagClassName() {
String tag = simpleClassName;
if (StringUtil.isNotEmpty(tableAnnotation.prefix()) || StringUtil.isNotEmpty(tableAnnotation.suffix())) {
tag = tableAnnotation.prefix() + tag + tableAnnotation.suffix();
} else {
tag = String.format(tableAnnotation.format(), tag);
if (tagClassName == null) {
tagClassName = parse(tableAnnotation.value(), this.simpleClassName);
}
return tag;
return tagClassName;
}
/**
* 生成类的路径
*/
public String getTagPackage() {
return classPackage + "." + tableAnnotation.packageName();
if (tagPackageName == null) {
tagPackageName = parse(tableAnnotation.packageName(), this.classPackage);
}
return tagPackageName;
}
private String parse(String expression, String source) {
String tag;
if (expression.toUpperCase().startsWith(OGNL_PREFIX)) {
String ognl = expression.substring(OGNL_PREFIX.length());
OgnlRoot root = new OgnlRoot(this.simpleClassName, this.classPackage);
OgnlContext context = Ognl.createDefaultContext(root);
try {
return Ognl.getValue(ognl, context, context.getRoot()).toString();
} catch (OgnlException e) {
throw new BuilderException("Error evaluating expression '" + ognl + "'. Cause: " + e, e);
}
} else {
tag = String.format(expression, source);
}
return tag;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getSimpleClassName() {
return simpleClassName;
}
public void setSimpleClassName(String simpleClassName) {
this.simpleClassName = simpleClassName;
}
public String getClassComment() {
return classComment;
}
@ -84,10 +106,6 @@ public class TableInfo {
return tableAnnotation;
}
public void setTableAnnotation(Table tableAnnotation) {
this.tableAnnotation = tableAnnotation;
}
public Set<FieldInfo> getFields() {
return fields;
}