gu.sql2java.generator.SqlComment Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sql2java-generator Show documentation
Show all versions of sql2java-generator Show documentation
executable jar of sql2java generator
The newest version!
package gu.sql2java.generator;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.gitee.l0km.com4j.base.Pair;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.common.collect.ImmutableMap;
import gu.sql2java.excel.annotations.ExcelColumn;
import gu.sql2java.excel.annotations.ExcelSheet;
import static com.google.common.base.Strings.nullToEmpty;
import static com.gitee.l0km.com4j.base.MiscellaneousUtils.elementsOf;
import static com.google.common.base.Preconditions.checkState;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* SQL 语句注释字段(COMMENT)自定义标记解析
* @author guyadong
*
*/
class SqlComment {
/**
* 正表达式提取字段注释({@link #remarks})中的JSON字段定义
*/
private static final String JSON_FIELD_REGEX="^(\\[JSON_STR(?:,(array|obj(?:ect)?|[a-z][\\w\\.]+\\w+))?\\])(.*)";
/**
* 正表达式提取字段注释({@link #remarks})中的字段名标记
*/
private static final String NAME_TAG_REGEX="X@NAME\\s*:(.+?)@X";
/**
* 正表达式提取字段注释({@link #remarks})中的多符号定义标记
*/
private static final String NAMES_TAG_REGEX="X@NAMES\\s*:\\s*((?:\\w+[=:-].+?,?)+)@X";
/**
* 正表达式提取字段注释({@link #remarks})中的多值转换定义标记
*/
private static final String VALUES_TAG_REGEX="X@VALUES\\s*:((?:.+?[=:-].+?,?)+)@X";
/**
* 正表达式提取字段注释({@link #remarks})中的ExcelColumn注解定义标记
*/
private static final String COLUMN_TAG_REGEX="X@COLUMN\\s*:((?:(?:\\s*\\w+\\s*)=(?:.+?),?)+?)@X";
/**
* 正表达式提取字段注释({@link #remarks})中的ExcelSheet注解定义标记
*/
private static final String SHEET_TAG_REGEX="X@SHEET\\s*:((?:(?:\\s*\\w+\\s*)=(?:.+?),?)+?)@X";
/**
* 正表达式提取字段注释({@link #remarks})中的NUM字段定义
*/
private static final String NUM_FIELD_REGEX="^(\\[NUM,(Boolean|Byte|Short|Integer|Long|Float|Double)\\])(.*)";
/**
* 正表达式提取字段注释({@link #remarks})中的ANN字段定义,用于插入Java注解代码
*/
private static final String ANNOT_FIELD_REGEX="ANN(@.+?)@NNA";
/**
* 正表达式提取字段注释({@link #remarks})中的JSAN字段定义,用于插入JSON序列化反序列化相关Java注解代码
*/
private static final String JSON_ANNOT_FIELD_REGEX="JSAN(@.+?)@NASJ";
/**
* 正表达式提取字段注释({@link #remarks})中的TYPE字段定义,用于插入Java注解代码
*/
private static final String TYPE_FIELD_REGEX="TYPE@(.+?)@EPYT";
/**
* 正表达式提取字段注释({@link #remarks})中的SCOPE字段定义
*
* - SCOPE@LOCAL@EPOSC -- 字段本地可见,在网络传输时不参与序列化反序列化
*
*/
private static final String SCOPE_FIELD_REGEX="SCOPE@(LOCAL|THRIFT|JSON)@EPOSC";
private static final Set EXCEL_COLUMN_FIELDS = methodNamesOf(ExcelColumn.class);
private static final Set EXCEL_SHEET_FIELDS = methodNamesOf(ExcelSheet.class);
private final String remarks;
/**
* 注解中NAME标记字段定义的字段名,如果没有定义NAME tag则为空字符串,参见{@link #NAME_TAG_REGEX}
* @see #setRemarks(String)
*/
private final String descName;
/**
* 注解中NAMES标记字段定义的多符号定义,如果没有定义NAMES tag则为空字符串,参见{@link #VALUES_TAG_REGEX}
* @see #setRemarks(String)
*/
private final String namesTag;
/**
* 注解中NAMES标记字段定义的多符号定义的名字映射,如果没有定义NAMES tag则为空,参见{@link #NAMES_TAG_REGEX}
* @see #setRemarks(String)
*/
private final Map namesTagMap;
/**
* 注解中VALUES标记字段定义的多符号定义列表,如果没有定义VALUES tag则为空字符串,参见{@link #VALUES_TAG_REGEX}
* @see #setRemarks(String)
*/
private final String valuesTag;
/**
* 注解中VALUES标记字段定义的多符号定义的名字映射,如果没有定义VALUES tag则为空,参见{@link #VALUES_TAG_REGEX}
* @see #setRemarks(String)
*/
private final Map valuesTagMap;
/**
* 注解中COLUMN标记字段定义的ExcelColumn字段定义列表,如果没有定义COLUMN tag则为空字符串,参见{@link #COLUMN_TAG_REGEX}
* @see #setRemarks(String)
*/
private final String columnTag;
/**
* 注解中COLUMN标记字段定义的ExcelColumn字段定义映射,如果没有定义COLUMN tag则为空,参见{@link #COLUMN_TAG_REGEX}
* @see #setRemarks(String)
*/
private final Map columnTagMap;
/**
* 注解中SHEET标记字段定义的ExcelSheet字段定义列表,如果没有定义SHEET tag则为空字符串,参见{@link #SHEET_TAG_REGEX}
* @see #setRemarks(String)
*/
private final String sheetTag;
/**
* 注解中SHEET标记字段定义的ExcelSheet字段定义映射,如果没有定义SHEET tag则为空,参见{@link #SHEET_TAG_REGEX}
* @see #setRemarks(String)
*/
private final Map sheetTagMap;
/**
* 删除{@code X@ @X}标记的注释字段信息
*/
private final String normalizedRemarks;
SqlComment(String remarks) {
this.remarks = nullToEmpty(remarks).replaceAll("/\\*", "SLASH*").replaceAll("\\*/", "*SLASH");
if(!Strings.isNullOrEmpty(this.remarks)){
{
/** 从注解中提取NAME标记字段定义的字段名保存到 descName成员 ,如果没有定义NAME tag则descName为空字符串 */
Matcher matcher=Pattern.compile(NAME_TAG_REGEX).matcher(this.remarks);
this.descName = matcher.find() ? matcher.group(1) : "";
}
{
ImmutableBiMap.builder();
/** 注解中提取NAMES标记字段定义的多符号定义保存到 namesTag成员,如果没有定义NAMES tag则namesTag为空字符串 */
Pair> pair = fetchMapDefine(NAMES_TAG_REGEX, ImmutableBiMap.builder());
this.namesTag = pair.getKey();
this.namesTagMap = new TreeMap<>(pair.getValue());
}
{
/** 注解中提取VALUES标记字段定义的多符号定义保存到 valuesTag成员,如果没有定义VALUES tag则valuesTag为空字符串 */
Pair> pair = fetchMapDefine(VALUES_TAG_REGEX, ImmutableBiMap.builder());
this.valuesTag = pair.getKey();
this.valuesTagMap = new TreeMap<>(pair.getValue());
}
{
/** 注解中提取COLUMN标记字段定义的多符号定义保存到 columnTag成员,如果没有定义COLUMN tag则columnTag为空字符串 */
Pair> pair = fetchMapDefine(COLUMN_TAG_REGEX, ImmutableMap.builder());
this.columnTag = pair.getKey();
this.columnTagMap = new TreeMap<>(Maps.filterKeys(pair.getValue(),
k->EXCEL_COLUMN_FIELDS.contains(k)));
}
{
/** 注解中提取SHEET标记字段定义的多符号定义保存到 sheetTag成员,如果没有定义SHEET tag则sheetTag为空字符串 */
Pair> pair = fetchMapDefine(SHEET_TAG_REGEX, ImmutableMap.builder());
this.sheetTag = pair.getKey();
this.sheetTagMap = new TreeMap<>(Maps.filterKeys(pair.getValue(),
k->EXCEL_SHEET_FIELDS.contains(k)));
}
this.normalizedRemarks = this.remarks
.replaceAll(NAME_TAG_REGEX, "$1")
.replaceAll(NAMES_TAG_REGEX, "$1")
.replaceAll(VALUES_TAG_REGEX, "$1")
.replaceAll(COLUMN_TAG_REGEX, "")
.replaceAll(SHEET_TAG_REGEX, "")
.replaceAll(JSON_FIELD_REGEX, "$3")
.replaceAll(NUM_FIELD_REGEX, "$3")
.replaceAll(JSON_ANNOT_FIELD_REGEX, "")
.replaceAll(ANNOT_FIELD_REGEX, "")
.replaceAll(TYPE_FIELD_REGEX, "")
.replaceAll(SCOPE_FIELD_REGEX, "");
}else{
this.descName = "";
this.namesTag = "";
this.namesTagMap = ImmutableBiMap.of();
this.valuesTag = "";
this.valuesTagMap = ImmutableBiMap.of();
this.columnTag = "";
this.columnTagMap = ImmutableBiMap.of();
this.sheetTag = "";
this.sheetTagMap = ImmutableBiMap.of();
this.normalizedRemarks = this.remarks;
}
}
/**
* @return normalized comment content
*/
String getRemarks() {
return normalizedRemarks;
}
/**
* 返回当前注解中NAME标记字段定义的字段名,如果没有定义NAME tag则返回空字符串,参见{@link #NAME_TAG_REGEX}
*/
String getDescName() {
return descName;
}
/**
* 返回当前注解中NAMES标记字段定义的多符号定义,如果没有定义NAMES tag则返回空字符串,参见{@link #VALUES_TAG_REGEX}
*/
String getNamesTag() {
return namesTag;
}
/**
* 返回注解中NAMES标记字段定义的多符号定义的名字映射,如果没有定义NAMES tag则为空
*/
Map getNamesTagMap() {
return namesTagMap;
}
/**
* 返回当前注解中VALUES标记字段定义的多符号定义,如果没有定义VALUES tag则返回空字符串,参见{@link #VALUES_TAG_REGEX}
*/
String getValuesTag() {
return valuesTag;
}
/**
* 返回注解中VALUES标记字段定义的多符号定义的名字映射,如果没有定义VALUES tag则为空
*/
Map getValuesTagMap() {
return valuesTagMap;
}
/**
* @return columnTag
*/
String getColumnTag() {
return columnTag;
}
/**
* @return columnTagMap
*/
Map getColumnTagMap() {
Map m = new TreeMap<>(columnTagMap);
/** 优先使用NAME tag定义的名字做name */
if(!descName.isEmpty()){
m.put("name",descName);
}
/** 优先使用NAME tag定义的名字做name */
if(!valuesTag.isEmpty()){
m.put("readConverterExp",valuesTag);
}
return m;
}
/**
* @return sheetTag
*/
String getSheetTag() {
return sheetTag;
}
/**
* @return sheetTagMap
*/
Map getSheetTagMap() {
Map m = new TreeMap<>(sheetTagMap);
/** 优先使用NAME tag定义的名字做title */
if(!descName.isEmpty()){
m.put("title",descName);
}
return m;
}
/**
* 返回当前字段的注释是否有JSON tag
*/
boolean hasJsonTag(){
return !Strings.isNullOrEmpty(remarks) && remarks.matches(JSON_FIELD_REGEX);
}
/**
* 返回当前字段的注释是否有NUM tag
*/
boolean hasNumTag(){
return !Strings.isNullOrEmpty(remarks) && remarks.matches(NUM_FIELD_REGEX);
}
/**
* 返回当前字段的注释是否有ANNOT tag
*/
boolean hasAnnotTag(){
return !Strings.isNullOrEmpty(remarks) && remarks.matches(ANNOT_FIELD_REGEX);
}
/**
* 从字段注释中根据正则表达式{@link #JSON_FIELD_REGEX}解析JSON的类型定义(fastjson)
* 根据{@code [JSON_STR,...]}的定义返回不同的JSON类:
*
* - [JSON_STR,array] ---- JSONArray
* - [JSON_STR,object],[JSON_STR,obj] ---- JSONObject
* - [JSON_STR] ---- JSON
*
* 如果不是JSON字段则返回{@code null}
*/
String getJsonType(){
Matcher matcher=Pattern.compile(JSON_FIELD_REGEX).matcher(remarks);
checkState(matcher.find(),"NOT FOUND JSON tag in comment : %s",remarks);
String g2 = matcher.group(2);
if("array".equals(g2)){
return JSONArray.class.getName();
}else if(null!= g2 && g2.matches("obj(?:ect)?")){
return JSONObject.class.getName();
}else if(null != g2){
return g2;
}
return JSONObject.class.getName();
}
/**
* 从字段注释中根据正则表达式{@link #NUM_FIELD_REGEX}解析定义的整数类型
* 根据{@code [NUM,...]}的定义返回不同的整数类型类:(Boolean|Byte|Short|Integer|Long|Float|Double),
* 如果不是NUM字段则返回{@code null}
*/
Class> getPrimitiveType(){
Matcher matcher=Pattern.compile(NUM_FIELD_REGEX).matcher(remarks);
if(!matcher.find()) {
return null;
}
String g2 = matcher.group(2);
switch(g2) {
case "Boolean":
return Boolean.class;
case "Byte":
return Byte.class;
case "Short":
return Short.class;
case "Integer":
return Integer.class;
case "Long":
return Long.class;
case "Float":
return Float.class;
case "Double":
return Double.class;
}
throw new IllegalStateException("UNSUPPORTED TYPE FOR " + g2);
}
/**
* 从字段注释中根据正则表达式{@link #ANNOT_FIELD_REGEX}解析ANN的注解定义列表
* 如果没有定义ANN字段则返回空
*/
List getAnnotations(){
List annots = Lists.newArrayList();
Matcher matcher=Pattern.compile(ANNOT_FIELD_REGEX).matcher(remarks);
while(matcher.find()) {
annots.add(matcher.group(1));
}
return annots;
}
/**
* 从字段注释中根据正则表达式{@link #JSON_ANNOT_FIELD_REGEX}解析JSAN的注解定义列表
* 如果没有定义JSAN字段则返回空
* @since 3.32.0
*/
List getJsonAnnotations(){
List annots = Lists.newArrayList();
Matcher matcher=Pattern.compile(JSON_ANNOT_FIELD_REGEX).matcher(remarks);
while(matcher.find()) {
annots.add(matcher.group(1));
}
return annots;
}
/**
* 从字段注释中根据正则表达式{@link #TYPE_FIELD_REGEX}解析TYPE的类型定义
* 如果不是TYPE字段则返回{@code null}
*/
String getFieldType(){
Matcher matcher=Pattern.compile(TYPE_FIELD_REGEX).matcher(remarks);
if(matcher.find()) {
return matcher.group(1);
}
return null;
}
/**
* 从字段注释中根据正则表达式{@link #SCOPE_FIELD_REGEX}解析TYPE的类型定义
* 如果不是TYPE字段则返回{@code null}
* @since 3.32.0
*/
String getScopeType(){
Matcher matcher=Pattern.compile(SCOPE_FIELD_REGEX).matcher(remarks);
if(matcher.find()) {
return matcher.group(1);
}
return null;
}
/**
* 注解中提取正则表达式定义的多符号定义保存到 Pair的key成员,
* 将符号定义的key-value映射保存到Pair的value字段
* 如果没有定义则key为空字符串,value为空
* @param builder Map builder
*/
@SuppressWarnings("unchecked")
private > Pair fetchMapDefine(String regex, M.Builder builder){
Matcher matcher=Pattern.compile(regex).matcher(this.remarks);
String namesTag = matcher.find() ? matcher.group(1) : "";
if(!namesTag.isEmpty()){
String[] def = namesTag.split(",");
for (String item : def){
String[] itemArray = item.split("[=:-]");
if(itemArray.length == 2){
String left = itemArray[0].trim();
String right = itemArray[1].trim();
if(!left.isEmpty()&& !right.isEmpty()){
builder.put(left, right);
}
}
}
}
M m = (M) builder.build();
namesTag = m.toString();
namesTag = namesTag.substring(1,namesTag.length()-1);
return new Pair(namesTag, m);
}
private static String formatValue(Class> type,String v){
if(String.class.isAssignableFrom(type)){
return "\"" + v + "\"";
}else if(Class.class.isAssignableFrom(type)){
return v.replaceAll("\\.class$", "") + ".class";
}
return v;
}
/**
* 返回注解类的所有方法名,输入参数为{@code null}返回空集合
* @param annotation
*/
private static Set methodNamesOf(Class extends Annotation> annClass) {
if(null != annClass){
return Sets.newLinkedHashSet(Lists.transform(Arrays.asList(annClass.getDeclaredMethods()),Method::getName));
}
return Collections.emptySet();
}
String getExcelAnnotation(Class extends Annotation>annotationType, Function headerColumns){
final Map tagMap ;
if(ExcelColumn.class.equals(annotationType)){
tagMap = getColumnTagMap();
}else if(ExcelSheet.class.equals(annotationType)){
tagMap = getSheetTagMap();
}else {
throw new IllegalArgumentException("@ExcelColumn or @ExcelSheet required for annotationType");
}
StringBuffer buffer = new StringBuffer("@"+annotationType.getSimpleName()+"(");
final AtomicInteger fillCount = new AtomicInteger(0);
if(null != headerColumns){
Integer c = headerColumns.apply(buffer);
if(null != c){
fillCount.addAndGet(c);
}
}
/** 注释字段(方法)排序输出 */
Ordering.natural()
.onResultOf(Method::getName)
.sortedCopy(Arrays.asList(annotationType.getDeclaredMethods()))
.forEach(m->{
String k = m.getName();
String v = tagMap.get(k);
if(null != v){
if(fillCount.get() > 0){
buffer.append(",");
}
Class> type = m.getReturnType();
if(type.isArray()){
Class> componentType = type.getComponentType();
String elements = Joiner.on(',').join(Lists.transform(elementsOf(v,"|"),s->formatValue(componentType, s)));
buffer.append(k + "={").append(elements).append("}");
}else{
buffer.append(k + "=").append(formatValue(type, v));
}
fillCount.incrementAndGet();
}
});
buffer.append(")");
return fillCount.get() > 0 ? buffer.toString() : null;
}
}