del[protobuf]: delete CodeBuilder of protobuf

This commit is contained in:
godotg
2023-12-03 14:48:41 +08:00
parent fc8d5b848f
commit c8b83210a0
2 changed files with 33 additions and 296 deletions
@@ -1,225 +0,0 @@
/*
* Copyright (C) 2020 The zfoo Authors
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.zfoo.protocol.serializer.protobuf.builder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/**
* 简易的代码构建器,方便进行行内的占位符,占位符采用$key$的形式方便预生成代码的阅读.
* 占位符采用下标的方式赋值$name$中间的字符会被忽略
*/
public class CodeBuilder {
private final StringBuilder code;
private static final String INDENT_CHARS = " ";
private static final String SHORT_INDENT_CHARS = "\t";
private static final String LINE_SPERATOR = "\n";
private final BlockingQueue<String> prepares;
private final BlockingQueue<String> args;
/**
* 使用紧凑的缩进,紧凑缩进使用一个"\t"tab键缩进的方式
*/
private boolean compactIdentation;
public CodeBuilder() {
code = new StringBuilder();
prepares = new ArrayBlockingQueue<>(40);
args = new ArrayBlockingQueue<>(40);
compactIdentation = false;
}
/**
* 向现有代码中缩进指定的级别
*
* @param level 缩进的级别
* @return
*/
public CodeBuilder t(int level) {
flush();
for (int i = 0; i < level; i++) {
if (!isCompactIdentation()) {
code.append(INDENT_CHARS);
} else {
code.append(SHORT_INDENT_CHARS);
}
}
return this;
}
/**
* 为占位符的表达式中占位符进行赋值
*
* @param arg 占位符赋值的字符串数组
* @return
*/
public CodeBuilder arg(String... arg) {
if (prepares.isEmpty()) {
return this;
}
for (String a : arg) {
args.offer(a);
}
if (args.size() >= prepares.size() - 1) {
flush();
}
return this;
}
/**
* 向代码中追加字符串
*
* @param str 需要追加的字符串
* @return
*/
public CodeBuilder c(String str) {
flush();
code.append(str);
return this;
}
/**
* 指定需要替换占位符的字符串,占位符使用"$$"包含,"$"内部的字符不会输出一个"$$"作为一个
* 占位符,如果需要输出"$"则使用"\"进行转义
*
* @param expression 需要替换占位符的表达式
* @return
*/
public CodeBuilder e(String expression) {
if (expression == null || expression.isEmpty()) {
return this;
}
flush();
char c;
boolean isStarted = false;
StringBuilder tmp = new StringBuilder();
for (int i = 0; i < expression.length(); i++) {
c = expression.charAt(i);
if (c == '$') {
isStarted = dealTmpData(tmp, c, isStarted);
} else {
tmp.append(c);
}
}
prepares.offer(tmp.toString());
return this;
}
/**
* 当出现$占位符时,判断解析状态并返回下一个字符的解析状态
*
* @param tmp 临时保存的数据
* @param c 当前的字符
* @param isStarted 当前解析的状态
* @return
*/
private boolean dealTmpData(StringBuilder tmp, char c, final boolean isStarted) {
boolean start = isStarted;
if (tmp.length() == 0) {
if (isStarted) {
start = false;
tmp.delete(0, tmp.length());
} else {
prepares.offer(tmp.toString());
start = true;
tmp.delete(0, tmp.length());
}
} else {
if (tmp.charAt(tmp.length() - 1) != '\\') {
if (isStarted) {
start = false;
tmp.delete(0, tmp.length());
} else {
prepares.offer(tmp.toString());
start = true;
tmp.delete(0, tmp.length());
}
} else {
tmp.setCharAt(tmp.length() - 1, c);
}
}
return start;
}
@Override
public String toString() {
flush();
return code.toString();
}
/**
* 刷新占位符替换后的字符串到现有代码中,当给定的变量个数多余占位符的个数时多余的变量
* 不会被输出
*
* @return
*/
public CodeBuilder flush() {
if (prepares.isEmpty()) {
args.clear();
return this;
}
int count = prepares.size();
String str;
for (int i = 0; i < count - 1; i++) {
str = prepares.poll();
if (str != null) {
code.append(str);
}
String val = args.poll();
if (val != null) {
code.append(val);
}
}
str = prepares.poll();
while (str != null) {
code.append(str);
str = prepares.poll();
}
args.clear();
return this;
}
/**
* 向代码中追加指定个数的换行符
*
* @param rows 换行符的个数
* @return
*/
public CodeBuilder ln(int rows) {
flush();
code.append(LINE_SPERATOR);
if (rows > 1) {
for (int i = 1; i < rows; i++) {
code.append(LINE_SPERATOR);
}
}
return this;
}
/**
* 向代码中追加一个换行符,如果有没有输出的占位符的字符串则会先追加占位符的字符串
*
* @return
*/
public CodeBuilder ln() {
return ln(1);
}
/**
* 使用紧凑的缩进,紧凑缩进使用一个"\t"tab键缩进的方式
*/
public boolean isCompactIdentation() {
return compactIdentation;
}
}
@@ -14,14 +14,20 @@
package com.zfoo.protocol.serializer.protobuf.builder;
import com.zfoo.protocol.collection.CollectionUtils;
import com.zfoo.protocol.serializer.protobuf.parser.Proto;
import com.zfoo.protocol.serializer.protobuf.parser.TypeJava;
import com.zfoo.protocol.serializer.protobuf.parser.TypeProtobuf;
import com.zfoo.protocol.serializer.protobuf.wire.*;
import com.zfoo.protocol.serializer.protobuf.parser.Proto;
import com.zfoo.protocol.serializer.protobuf.wire.MapField;
import com.zfoo.protocol.serializer.protobuf.wire.Option;
import com.zfoo.protocol.serializer.protobuf.wire.PbField;
import com.zfoo.protocol.serializer.protobuf.wire.ProtoMessage;
import com.zfoo.protocol.util.StringUtils;
import java.util.*;
import static com.zfoo.protocol.util.FileUtils.LS;
import static com.zfoo.protocol.util.StringUtils.TAB;
public class JavaBuilder {
private static final List<String> BASE_TYPES;
@@ -64,15 +70,6 @@ public class JavaBuilder {
}
}
public String getAnnotationType(PbField field) {
String type = field.getTypeString();
if (BASE_TYPES.contains(type.toLowerCase(Locale.ENGLISH))) {
return "Type." + TypeProtobuf.valueOf(type.toUpperCase(Locale.ENGLISH));
} else {
return "Type." + TypeProtobuf.MESSAGE;
}
}
private void buildMsgImps(ProtoMessage msg, List<PbField> tmp, List<String> imps) {
var fields = msg.getFields();
if (CollectionUtils.isNotEmpty(fields)) {
@@ -91,20 +88,20 @@ public class JavaBuilder {
}
}
private void buildDocComment(CodeBuilder cb, ProtoMessage msg) {
private void buildDocComment(StringBuilder builder, ProtoMessage msg) {
if (CollectionUtils.isEmpty(msg.getComments())) {
return;
}
cb.t(0).c("/**").ln();
msg.getComments().forEach(c -> cb.t(0).c(" * ").c(c).ln());
cb.t(0).c(" */").ln();
builder.append("/**").append(LS);
msg.getComments().forEach(it -> builder.append(StringUtils.format(" * {}", it)).append(LS));
builder.append(" */").append(LS);
}
private void buildFieldComment(CodeBuilder cb, PbField pbField) {
private void buildFieldComment(StringBuilder builder, PbField pbField) {
if (CollectionUtils.isEmpty(pbField.getComments())) {
return;
}
pbField.getComments().forEach(c -> cb.t(1).c("// ").c(c).ln());
pbField.getComments().forEach(it -> builder.append(TAB).append(StringUtils.format("// {}", it)).append(LS));
}
private String getJavaPackage(Proto proto) {
@@ -125,41 +122,25 @@ public class JavaBuilder {
var imps = new ArrayList<String>();
var builder = new StringBuilder();
var cb = new CodeBuilder();
buildMsgImps(msg, tmp, imps);
List<PbField> fields = new ArrayList<>();
tmp.stream().sorted(Comparator.comparingInt(PbField::getTag))
.forEach(fields::add);
// not nested
imps.stream().sorted(Comparator.naturalOrder())
.forEach(e -> cb.t(level - 1).e("import $cls$;").arg(e).ln());
.forEach(it -> builder.append(StringUtils.format("import {};", it)).append(LS));
cb.ln();
buildDocComment(cb, msg);
cb.t(level - 1).e("public class $name$ {").arg(msg.getName()).ln(2);
CodeBuilder getCode;
CodeBuilder setCode;
buildDocComment(builder, msg);
builder.append(StringUtils.format("public class {} {", msg.getName())).append(LS);
int size = fields.size();
List<String> getCodes = new ArrayList<>(size);
List<String> setCodes = new ArrayList<>(size);
CodeBuilder cons = new CodeBuilder();
var builderMethod = new StringBuilder();
for (int i = 0; i < size; i++) {
PbField f = fields.get(i);
getCode = new CodeBuilder();
setCode = new CodeBuilder();
String typeName = getAnnotationType(f);
if (msg.getName().equals("Type")) {
typeName = Proto.class.getPackage().getName() + ".wire.Field." + typeName;
}
buildFieldComment(cb, f);
buildFieldComment(builder, f);
String type = getJavaType(f);
String name = f.getName();
if (f.getCardinality() == PbField.Cardinality.REPEATED) {
@@ -167,47 +148,28 @@ public class JavaBuilder {
type = "List<" + boxedTypeName + ">";
}
cb.t(level).e("private $type$ $name$;")
.arg(type, name).ln();
builder.append(TAB).append(StringUtils.format("private {} {};", type, name)).append(LS);
String getMethod;
if (!"bool".equalsIgnoreCase(f.getType())) {
getMethod = "get" +
f.getName().substring(0, 1).toUpperCase(Locale.ENGLISH) +
f.getName().substring(1);
getMethod = StringUtils.format("get{}", StringUtils.capitalize(f.getName()));
} else {
getMethod = "is" +
f.getName().substring(0, 1).toUpperCase(Locale.ENGLISH) +
f.getName().substring(1);
getMethod = StringUtils.format("is{}", StringUtils.capitalize(f.getName()));
}
getCode.t(level).e("public $type$ $getMethod$() {")
.arg(type, getMethod).ln();
getCode.t(level + 1).e("return $name$;").arg(f.getName()).ln();
getCode.t(level).c("}").ln();
getCodes.add(getCode.toString());
String retType = "void";
String setMethod = "set" +
f.getName().substring(0, 1).toUpperCase(Locale.ENGLISH) +
f.getName().substring(1);
setCode.t(level).e("public $retType$ $setMethod$($type$ $name$) {")
.arg(retType, setMethod, type, name).ln();
setCode.t(level + 1).e("this.$name$ = $name$;")
.arg(f.getName(), f.getName()).ln();
setCode.t(level).c("}").ln();
setCodes.add(setCode.toString());
builderMethod.append(TAB).append(StringUtils.format("public {} {}() {", type, getMethod)).append(LS);
builderMethod.append(TAB + TAB).append(StringUtils.format("return {};", f.getName())).append(LS);
builderMethod.append(TAB).append("}").append(LS);
String setMethod = StringUtils.format("set{}", StringUtils.capitalize(f.getName()));
builderMethod.append(TAB).append(StringUtils.format("public void {}({} {}) {", setMethod, type, f.getName())).append(LS);
builderMethod.append(TAB + TAB).append(StringUtils.format("this.{} = {};", f.getName(), f.getName())).append(LS);
builderMethod.append(TAB).append("}").append(LS);
}
cb.ln().c(cons.toString());
for (int i = 0; i < size; i++) {
cb.ln().c(getCodes.get(i));
cb.ln().c(setCodes.get(i));
}
cb.t(level - 1).c("}");
return cb.toString();
builder.append(LS).append(builderMethod);
builder.append("}");
return builder.toString();
}
private String getBoxedTypeName(PbField f) {