mirror of
https://github.com/tiennm99/zfoo.git
synced 2026-10-13 06:15:51 +00:00
feat[protobuf]: generate pojo file from proto of protobuf
This commit is contained in:
1 parent
f6aa27cb1d
commit
c1b859c8c3
28 files changed
+4348
-1
No files matched your search
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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;
|
||||
|
||||
import com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.serializer.protobuf.codegen.IfaceGenerator;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.parser.Proto;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.parser.ProtoParser;
|
||||
import com.zfoo.protocol.util.FileUtils;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GeneratePbUtils {
|
||||
|
||||
public static void create(PbBuildOption buildOption) {
|
||||
var protoPathFile = new File(buildOption.getProtoPath());
|
||||
if (!protoPathFile.exists()) {
|
||||
throw new RuntimeException(StringUtils.format("proto path:[{}] not exist", buildOption.getProtoPath()));
|
||||
}
|
||||
|
||||
var protoFiles = FileUtils.getAllReadableFiles(protoPathFile)
|
||||
.stream()
|
||||
.filter(it -> it.getName().toLowerCase().endsWith(".proto"))
|
||||
.toList();
|
||||
|
||||
if (CollectionUtils.isEmpty(protoFiles)) {
|
||||
throw new RuntimeException(StringUtils.format("There are no proto files to build in proto path:[{}]", buildOption.getProtoPath()));
|
||||
}
|
||||
|
||||
var srcPath = new File(buildOption.getOutputPath());
|
||||
|
||||
var protos = parseProtoFile(protoFiles);
|
||||
IfaceGenerator ifaceGenerator = new IfaceGenerator(srcPath, protos);
|
||||
ifaceGenerator.generate();
|
||||
}
|
||||
|
||||
public static List<Proto> parseProtoFile(List<File> protoFiles) {
|
||||
var protos = new ArrayList<Proto>();
|
||||
for (var protoFile : protoFiles) {
|
||||
var strs = FileUtils.readFileToStringList(protoFile)
|
||||
.stream()
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.toArray();
|
||||
var protoString = StringUtils.joinWith(FileUtils.LS, strs);
|
||||
if (StringUtils.isBlank(protoString)) {
|
||||
continue;
|
||||
}
|
||||
ProtoParser parser = new ProtoParser(protoString);
|
||||
Proto proto = parser.parse();
|
||||
proto.setFile(protoFile);
|
||||
protos.add(proto);
|
||||
}
|
||||
return protos;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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;
|
||||
|
||||
public class PbBuildOption {
|
||||
|
||||
private String protoPath;
|
||||
private String outputPath;
|
||||
private boolean isNested;
|
||||
|
||||
public String getProtoPath() {
|
||||
return protoPath;
|
||||
}
|
||||
|
||||
public void setProtoPath(String protoPath) {
|
||||
this.protoPath = protoPath;
|
||||
}
|
||||
|
||||
public String getOutputPath() {
|
||||
return outputPath;
|
||||
}
|
||||
|
||||
public void setOutputPath(String outputPath) {
|
||||
this.outputPath = outputPath;
|
||||
}
|
||||
|
||||
public boolean isIsNested() {
|
||||
return isNested;
|
||||
}
|
||||
|
||||
public PbBuildOption setIsNested(boolean isNested) {
|
||||
this.isNested = isNested;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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 com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.serializer.protobuf.PbBuildOption;
|
||||
import com.zfoo.protocol.serializer.protobuf.internal.CodeBuilder;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.*;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.Field.Type;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.ProtoEnum.EnumEntry;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.WireFormat.JavaType;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.parser.Proto;
|
||||
import com.zfoo.protocol.util.StringUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class JavaBuilder {
|
||||
private static final List<String> BASE_TYPES;
|
||||
|
||||
static {
|
||||
BASE_TYPES = new ArrayList<>();
|
||||
String[] types = ("double,float,int32,int64,uint32,uint64,sint32,sint64,"
|
||||
+ "fixed32,fixed64,sfixed32,sfixed64,bool,string,bytes").split(",");
|
||||
BASE_TYPES.addAll(Arrays.asList(types));
|
||||
}
|
||||
|
||||
|
||||
private String getOptionJavaType(List<Option> options) {
|
||||
String jType = "";
|
||||
if (options != null && !options.isEmpty()) {
|
||||
for (Option option : options) {
|
||||
if ("java_type".equals(option.getName())) {
|
||||
jType = option.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
return jType;
|
||||
}
|
||||
|
||||
public String getJavaType(Field field, List<String> imps, PbBuildOption buildOps) {
|
||||
String type = field.getTypeString();
|
||||
if (field instanceof MapField) {
|
||||
MapField mf = (MapField) field;
|
||||
type = "Map<" + getJavaType(mf.getKey().value()) + ", "
|
||||
+ getJavaType(mf.getValue()) + ">";
|
||||
return type;
|
||||
}
|
||||
String jType = getOptionJavaType(field.getOptions());
|
||||
if (!BASE_TYPES.contains(type.toLowerCase(Locale.ENGLISH))) {
|
||||
return type;
|
||||
}
|
||||
JavaType javaType = null;
|
||||
javaType = Type.valueOf(type.toUpperCase(Locale.ENGLISH)).javaType();
|
||||
if (javaType != null && javaType.getTypeString() != null) {
|
||||
String optionJavaType = getOptionJavaType(field.getOptions());
|
||||
if (optionJavaType == null || optionJavaType.isEmpty()) {
|
||||
type = javaType.getTypeString();
|
||||
} else {
|
||||
int lastDot = optionJavaType.lastIndexOf(".");
|
||||
if (lastDot == -1) {
|
||||
type = optionJavaType;
|
||||
} else {
|
||||
if (!imps.contains(optionJavaType)) {
|
||||
imps.add(optionJavaType);
|
||||
}
|
||||
type = optionJavaType.substring(lastDot + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ("int64".equals(field.getType()) && jType != null) {
|
||||
switch (jType) {
|
||||
case "LocalDateTime":
|
||||
addImport(imps, "java.time.LocalDateTime");
|
||||
type = jType;
|
||||
break;
|
||||
case "LocalDate":
|
||||
type = jType;
|
||||
addImport(imps, "java.time.LocalDate");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private void addImport(List<String> imps, String imp) {
|
||||
if (imps == null) {
|
||||
return;
|
||||
}
|
||||
if (!imps.contains(imp)) {
|
||||
imps.add(imp);
|
||||
}
|
||||
}
|
||||
|
||||
public String getJavaType(String type) {
|
||||
if (BASE_TYPES.contains(type.toLowerCase(Locale.ENGLISH))) {
|
||||
return Type.valueOf(type.toUpperCase(Locale.ENGLISH)).javaType().getTypeString();
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAnnotationType(Field field, Proto proto, Map<String, ProtoEnum> protoEnums) {
|
||||
String type = field.getTypeString();
|
||||
if (BASE_TYPES.contains(type.toLowerCase(Locale.ENGLISH))) {
|
||||
return "Type." + Type.valueOf(type.toUpperCase(Locale.ENGLISH));
|
||||
} else {
|
||||
String name = getJavaPackage(proto) + "." + type;
|
||||
if (protoEnums.containsKey(name)) {
|
||||
return "Type." + Type.ENUM;
|
||||
} else {
|
||||
return "Type." + Type.MESSAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildMsgImps(ProtoMessage msg, List<Field> tmp, List<String> imps,
|
||||
PbBuildOption buildOps) {
|
||||
if (msg.getFields() != null) {
|
||||
msg.getFields().forEach(e -> {
|
||||
getJavaType(e, imps, buildOps);
|
||||
tmp.add(e);
|
||||
});
|
||||
}
|
||||
List<Oneof> oneofs = msg.getOneofs();
|
||||
if (oneofs != null) {
|
||||
oneofs.forEach(o -> {
|
||||
if (o.getFields() != null) {
|
||||
o.getFields().forEach(tmp::add);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < tmp.size(); i++) {
|
||||
if (tmp.get(i) instanceof MapField) {
|
||||
addImport(imps, "java.util.Map");
|
||||
} else if (tmp.get(i).getCardinality() == Field.Cardinality.REPEATED) {
|
||||
addImport(imps, "java.util.List");
|
||||
addImport(imps, "java.util.ArrayList");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void buildDocComment(CodeBuilder cb, Comment comment, int level) {
|
||||
if (comment == null || comment.getLines() == null || comment.getLines().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
cb.t(level).c("/**").ln();
|
||||
comment.getLines().forEach(c -> cb.t(level).c(" * ").c(c).ln());
|
||||
cb.t(level).c(" */").ln();
|
||||
}
|
||||
|
||||
private Map<String, ProtoEnum> getAllProtoEnum(Proto proto, Map<String, Proto> protos) {
|
||||
Map<String, ProtoEnum> allEnums = new HashMap<>();
|
||||
List<ProtoEnum> protoEnums = proto.getEnums();
|
||||
if (protoEnums != null && !protoEnums.isEmpty()) {
|
||||
for (ProtoEnum protoEnum : protoEnums) {
|
||||
String packName = proto.getProtoPackage();
|
||||
String javaPack = getJavaPackage(proto);
|
||||
if (javaPack != null && javaPack.trim().length() > 0) {
|
||||
packName = javaPack;
|
||||
}
|
||||
allEnums.put(packName + "." + protoEnum.getName(), protoEnum);
|
||||
}
|
||||
}
|
||||
List<String> impProtos = proto.getImports();
|
||||
if (impProtos == null || impProtos.isEmpty()) {
|
||||
return allEnums;
|
||||
}
|
||||
for (String protoName : impProtos) {
|
||||
Proto impProto = protos.get(protoName);
|
||||
if (impProto == null) {
|
||||
continue;
|
||||
}
|
||||
allEnums.putAll(getAllProtoEnum(impProto, protos));
|
||||
}
|
||||
return allEnums;
|
||||
}
|
||||
|
||||
private String getJavaPackage(Proto proto) {
|
||||
if (CollectionUtils.isEmpty(proto.getOptions())) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
for (Option option : proto.getOptions()) {
|
||||
if ("java_package".equalsIgnoreCase(option.getName())) {
|
||||
return option.getValue();
|
||||
}
|
||||
}
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
|
||||
public String buildMessage(Proto proto, ProtoMessage msg, int indent, Map<String, String> defineMsgs, PbBuildOption buildOps, Map<String, Proto> protos) {
|
||||
Map<String, ProtoEnum> protoEnums = getAllProtoEnum(proto, protos);
|
||||
int level = Math.max(indent, 1);
|
||||
final CodeBuilder cb = new CodeBuilder();
|
||||
List<Field> tmp = new ArrayList<>();
|
||||
List<String> imps = new ArrayList<>();
|
||||
buildMsgImps(msg, tmp, imps, buildOps);
|
||||
|
||||
List<Field> fields = new ArrayList<>();
|
||||
tmp.stream().sorted(Comparator.comparingInt(Field::getTag))
|
||||
.forEach(fields::add);
|
||||
|
||||
if (!buildOps.isIsNested()) {
|
||||
imps.stream().sorted(Comparator.naturalOrder())
|
||||
.forEach(e -> cb.t(level - 1).e("import $cls$;").arg(e).ln());
|
||||
}
|
||||
cb.ln();
|
||||
buildDocComment(cb, msg.getComment(), level - 1);
|
||||
cb.t(level - 1).e("public class $name$ {").arg(msg.getName()).ln(2);
|
||||
|
||||
CodeBuilder getCode;
|
||||
CodeBuilder setCode;
|
||||
|
||||
int size = fields.size();
|
||||
|
||||
List<String> getCodes = new ArrayList<>(size);
|
||||
List<String> setCodes = new ArrayList<>(size);
|
||||
|
||||
CodeBuilder cons = new CodeBuilder();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Field f = fields.get(i);
|
||||
getCode = new CodeBuilder();
|
||||
setCode = new CodeBuilder();
|
||||
|
||||
String typeName = getAnnotationType(f, proto, protoEnums);
|
||||
if (msg.getName().equals("Type")) {
|
||||
typeName = Proto.class.getPackage().getName() + ".wire.Field." + typeName;
|
||||
}
|
||||
buildDocComment(cb, f.getComment(), level);
|
||||
String type = getJavaType(f, imps, buildOps);
|
||||
String name = f.getName();
|
||||
if (f.getCardinality() == Field.Cardinality.REPEATED) {
|
||||
String boxedTypeName = getBoxedTypeName(f, buildOps);
|
||||
type = "List<" + boxedTypeName + ">";
|
||||
}
|
||||
|
||||
cb.t(level).e("private $type$ $name$;")
|
||||
.arg(type, name).ln();
|
||||
|
||||
String getMethod;
|
||||
if (!"bool".equalsIgnoreCase(f.getType())) {
|
||||
getMethod = "get" +
|
||||
f.getName().substring(0, 1).toUpperCase(Locale.ENGLISH) +
|
||||
f.getName().substring(1);
|
||||
} else {
|
||||
getMethod = "is" +
|
||||
f.getName().substring(0, 1).toUpperCase(Locale.ENGLISH) +
|
||||
f.getName().substring(1);
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
cb.ln().c(cons.toString());
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
cb.ln().c(getCodes.get(i));
|
||||
cb.ln().c(setCodes.get(i));
|
||||
}
|
||||
|
||||
nestMessageMessage(proto, cb, msg.getMessages(), defineMsgs, level, protos);
|
||||
nestMessageEnum(cb, msg.getEnums(), level);
|
||||
|
||||
cb.t(level - 1).c("}");
|
||||
return cb.toString();
|
||||
}
|
||||
|
||||
private String getBoxedTypeName(Field f, PbBuildOption buildOps) {
|
||||
String type = getJavaType(f, null, buildOps);
|
||||
if (BASE_TYPES.contains(f.getTypeString())) {
|
||||
JavaType javaType = null;
|
||||
javaType = Type.valueOf(f.getTypeString().toUpperCase(Locale.ENGLISH)).javaType();
|
||||
if (javaType != null && javaType.getTypeString() != null) {
|
||||
type = javaType.getBoxedType();
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
private void nestMessageMessage(Proto proto, CodeBuilder cb,
|
||||
List<ProtoMessage> msgs, Map<String, String> defineMsgs,
|
||||
int level, Map<String, Proto> protos) {
|
||||
if (msgs == null || msgs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
cb.ln();
|
||||
PbBuildOption nestedOps = new PbBuildOption();
|
||||
nestedOps.setIsNested(true);
|
||||
msgs.stream().sorted(Comparator.comparing(ProtoMessage::getName))
|
||||
.forEach(e -> cb.c(buildMessage(proto, e, level + 1, defineMsgs, nestedOps, protos)));
|
||||
}
|
||||
|
||||
private void nestMessageEnum(CodeBuilder cb, List<ProtoEnum> enums, int indent) {
|
||||
if (enums == null || enums.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
cb.ln();
|
||||
PbBuildOption nestedOps = new PbBuildOption();
|
||||
nestedOps.setIsNested(true);
|
||||
enums.stream()
|
||||
.sorted(Comparator.comparing(ProtoEnum::getName))
|
||||
.forEach(e -> cb.c(buildEnum(e, indent + 1, nestedOps)).ln(2));
|
||||
|
||||
}
|
||||
|
||||
private String getFillSpaces(int count) {
|
||||
if (count <= 0) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < count; i++) {
|
||||
sb.append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String buildEnum(ProtoEnum protoEnum, final int indent, PbBuildOption buildOps) {
|
||||
int level = (indent < 1) ? 1 : indent;
|
||||
CodeBuilder cb = new CodeBuilder();
|
||||
|
||||
cb.t(level - 1).e("public enum $name$ {").arg(protoEnum.getName()).ln();
|
||||
List<EnumEntry> entries = protoEnum.getEntries();
|
||||
if (entries != null && !entries.isEmpty()) {
|
||||
Optional<EnumEntry> maxLen = entries.stream()
|
||||
.max(Comparator.comparingInt(e -> e.getLabel().length()));
|
||||
int len = maxLen.isPresent() ? maxLen.get().getLabel().length() : 1;
|
||||
|
||||
List<EnumEntry> es = new ArrayList<>();
|
||||
entries.stream()
|
||||
.sorted(Comparator.comparingInt(EnumEntry::getValue))
|
||||
.forEach(es::add);
|
||||
CodeBuilder vsb = new CodeBuilder();
|
||||
CodeBuilder psb = new CodeBuilder();
|
||||
for (int i = 0; i < es.size(); i++) {
|
||||
EnumEntry o = es.get(i);
|
||||
String sep = (i != es.size() - 1) ? "," : ";";
|
||||
String spaces = getFillSpaces(len - o.getLabel().length());
|
||||
String[] args = new String[]{o.getLabel(), spaces,
|
||||
String.valueOf(o.getValue()), sep};
|
||||
cb.t(level).e("$label$$spaces$($value$)$;$").arg(args).ln();
|
||||
|
||||
psb.t(level).e("public static final int $lable$_VALUE = $value$;")
|
||||
.arg(o.getLabel(), String.valueOf(o.getValue())).ln();
|
||||
|
||||
vsb.t(level + 2).e("case $value$:").arg(String.valueOf(o.getValue())).ln();
|
||||
vsb.t(level + 3).e("return $name$.$label$;")
|
||||
.arg(protoEnum.getName(), o.getLabel()).ln();
|
||||
}
|
||||
cb.ln();
|
||||
|
||||
cb.c(psb.toString()).ln();
|
||||
|
||||
cb.t(level).c("private final int value;").ln(2);
|
||||
|
||||
cb.t(level).e("private $label$(int value) {").arg(protoEnum.getName()).ln();
|
||||
cb.t(level + 1).c("this.value = value;").ln();
|
||||
cb.t(level).c("}").ln();
|
||||
|
||||
cb.t(level).c("public int getValue() {").ln();
|
||||
cb.t(level + 1).c("return this.value;").ln();
|
||||
cb.t(level).c("}").ln(2);
|
||||
|
||||
cb.t(level).e("public static $name$ valueOf(int value) {")
|
||||
.arg(protoEnum.getName()).ln();
|
||||
cb.t(level + 1).c("switch (value) {").ln();
|
||||
cb.c(vsb.toString());
|
||||
cb.t(level + 2).c("default:").ln();
|
||||
cb.t(level + 3).e("throw new IllegalArgumentException("
|
||||
+ "\"no enum value $value$ \" + value);")
|
||||
.arg(protoEnum.getName()).ln();
|
||||
|
||||
cb.t(level + 1).c("}").ln();
|
||||
cb.t(level).c("}").ln();
|
||||
}
|
||||
cb.t(level - 1).c("}");
|
||||
|
||||
return cb.toString();
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.codegen;
|
||||
|
||||
import com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.serializer.protobuf.PbBuildOption;
|
||||
import com.zfoo.protocol.serializer.protobuf.builder.JavaBuilder;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.Option;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.ProtoEnum;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.ProtoMessage;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.parser.Proto;
|
||||
import com.zfoo.protocol.util.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class IfaceGenerator {
|
||||
private final File srcPath;
|
||||
private final List<Proto> files;
|
||||
|
||||
public IfaceGenerator(File srcPath, List<Proto> files) {
|
||||
this.srcPath = srcPath;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
|
||||
public void generate() {
|
||||
List<Proto> protos = files;
|
||||
Map<String, Proto> allProtos = new HashMap<>();
|
||||
for (Proto proto : protos) {
|
||||
allProtos.put(proto.getName(), proto);
|
||||
}
|
||||
protos.forEach(p -> {
|
||||
generateProtoItem(p, allProtos);
|
||||
});
|
||||
}
|
||||
|
||||
private void generateProtoItem(Proto proto, Map<String, Proto> protos) {
|
||||
List<Option> options = proto.getOptions();
|
||||
Map<String, String> protoOptions = new HashMap<>();
|
||||
if (options != null) {
|
||||
options.forEach(o -> protoOptions.put(o.getName(), o.getValue()));
|
||||
}
|
||||
|
||||
PbBuildOption buildOps = new PbBuildOption();
|
||||
|
||||
generateDtoMessage(proto, buildOps, protos);
|
||||
}
|
||||
|
||||
public void generateDtoMessage(Proto proto, PbBuildOption buildOps, Map<String, Proto> protos) {
|
||||
JavaBuilder builder = new JavaBuilder();
|
||||
|
||||
Map<String, String> msgComments = new HashMap<>();
|
||||
List<ProtoEnum> enums = proto.getEnums();
|
||||
if (CollectionUtils.isNotEmpty(enums)) {
|
||||
String enumPath = srcPath + File.separator;
|
||||
enums.stream().sorted(Comparator.comparing(ProtoEnum::getName))
|
||||
.forEach(it -> {
|
||||
var code = builder.buildEnum(it, 1, buildOps);
|
||||
var filePath = enumPath + File.separator + it.getName() + ".java";
|
||||
FileUtils.writeStringToFile(new File(filePath), code, false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
List<ProtoMessage> msgs = proto.getMessages();
|
||||
if (CollectionUtils.isNotEmpty(msgs)) {
|
||||
String msgPath = srcPath + File.separator;
|
||||
msgs.stream()
|
||||
.sorted(Comparator.comparing(ProtoMessage::getName))
|
||||
.forEach(it -> {
|
||||
StringBuilder mc = new StringBuilder();
|
||||
if (it.getComment() != null) {
|
||||
mc.append(it.getComment());
|
||||
} else {
|
||||
if (it.getComment() != null && it.getComment().getLines() != null) {
|
||||
it.getComment().getLines().forEach(c -> mc.append(c));
|
||||
}
|
||||
}
|
||||
msgComments.put(it.getName(), mc.toString());
|
||||
var code = builder.buildMessage(proto, it, 1, null, buildOps, protos);
|
||||
var filePath = msgPath + File.separator + it.getName() + ".java";
|
||||
FileUtils.writeStringToFile(new File(filePath), code, false);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+226
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.internal;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* proto文件中注释的结构定义
|
||||
*/
|
||||
public class Comment {
|
||||
|
||||
|
||||
public enum CommentType {
|
||||
/**
|
||||
* 以"//"开头的注释类型
|
||||
*/
|
||||
INLINE,
|
||||
/**
|
||||
* 以 "/*"开头的注释类型
|
||||
*/
|
||||
MULTILINE,
|
||||
/**
|
||||
* 以 "/**"开头的注释类型
|
||||
*/
|
||||
DOCUMENT
|
||||
}
|
||||
|
||||
/**
|
||||
* 注释内容文本行列表
|
||||
*/
|
||||
private List<String> lines;
|
||||
/**
|
||||
* 注释的类型
|
||||
*/
|
||||
private CommentType type = CommentType.INLINE;
|
||||
|
||||
/**
|
||||
* 注释内容文本行列表
|
||||
*/
|
||||
public List<String> getLines() {
|
||||
if (lines == null) {
|
||||
lines = new ArrayList<>();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
public void setLines(List<String> lines) {
|
||||
if (lines instanceof ArrayList) {
|
||||
this.lines = lines;
|
||||
} else {
|
||||
getLines();
|
||||
this.lines.addAll(lines);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 注释的类型
|
||||
*/
|
||||
public CommentType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(CommentType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* protocol buffer扩展信息的定义
|
||||
*/
|
||||
public class Extend {
|
||||
private Comment comment;
|
||||
private String name;
|
||||
private List<Field> fields;
|
||||
|
||||
public Extend setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Extend setComment(Comment comment) {
|
||||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Comment getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public Extend addField(Field field) {
|
||||
if (field == null) {
|
||||
return this;
|
||||
}
|
||||
getFields().add(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Field> getFields() {
|
||||
if (fields == null) {
|
||||
fields = new ArrayList<>();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
public void setFields(List<Field> fields) {
|
||||
if (fields instanceof ArrayList) {
|
||||
this.fields = fields;
|
||||
} else {
|
||||
getFields().addAll(fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.parser.ProtoParser;
|
||||
|
||||
/**
|
||||
* protocol buffer 扩展tag的结构定义
|
||||
*/
|
||||
public class Extensions {
|
||||
|
||||
/**
|
||||
* 扩展开始的Tag编号
|
||||
*/
|
||||
private int startTag;
|
||||
/**
|
||||
* 扩展结束的Tag编号
|
||||
*/
|
||||
private int endTag;
|
||||
|
||||
public Extensions setEndTag(int endTag) {
|
||||
this.endTag = endTag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEndTag() {
|
||||
return endTag;
|
||||
}
|
||||
|
||||
public Extensions setStartTag(int startTag) {
|
||||
this.startTag = startTag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getStartTag() {
|
||||
return startTag;
|
||||
}
|
||||
|
||||
public static Extensions parseExtensions(String expression) {
|
||||
String exp = expression.trim();
|
||||
if (exp.isEmpty()) {
|
||||
throw new RuntimeException("extensions expression is empty");
|
||||
}
|
||||
int index = exp.indexOf("to");
|
||||
if (index < 0) {
|
||||
throw new RuntimeException("extensions expression must be start to end");
|
||||
}
|
||||
String sstart = exp.substring(0, index).trim();
|
||||
if (sstart.isEmpty()) {
|
||||
throw new RuntimeException("extensions expression start empty");
|
||||
}
|
||||
int start = ProtoParser.parseInt(sstart);
|
||||
if (start < 1) {
|
||||
throw new RuntimeException("extensions expression start cann't be " + start);
|
||||
}
|
||||
String sEnd = exp.substring(index + 2).trim();
|
||||
if (sEnd.isEmpty()) {
|
||||
throw new RuntimeException("extensions expression end empty");
|
||||
}
|
||||
int end;
|
||||
if ("max".equalsIgnoreCase(sEnd)) {
|
||||
end = WireFormat.MAX_TAG_VALUE;
|
||||
} else {
|
||||
end = ProtoParser.parseInt(sEnd);
|
||||
}
|
||||
if (end <= start) {
|
||||
throw new RuntimeException("extensions start tag <= end tag");
|
||||
}
|
||||
Extensions ext = new Extensions();
|
||||
ext.setStartTag(start).setEndTag(end);
|
||||
return ext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* protocol buffer协议消息体属性数据类型定义
|
||||
*/
|
||||
public class Field {
|
||||
/**
|
||||
* 属性是否赋值类型
|
||||
*/
|
||||
public enum Cardinality {
|
||||
/**
|
||||
* 未知类型
|
||||
*/
|
||||
UNKNOWN("unknown"),
|
||||
/**
|
||||
* 必须赋值
|
||||
*/
|
||||
REQUIRED("required"),
|
||||
/**
|
||||
* 可以不赋值
|
||||
*/
|
||||
OPTIONAL("optional"),
|
||||
/**
|
||||
* 可以赋多个值
|
||||
*/
|
||||
REPEATED("repeated");
|
||||
|
||||
private final String value;
|
||||
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
Cardinality(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
FLOAT("float", WireFormat.JavaType.FLOAT, WireType.FIXED32),
|
||||
DOUBLE("double", WireFormat.JavaType.DOUBLE, WireType.FIXED64),
|
||||
INT32("int32", WireFormat.JavaType.INT, WireType.VARINT),
|
||||
INT64("int64", WireFormat.JavaType.LONG, WireType.VARINT),
|
||||
UINT32("uint32", WireFormat.JavaType.INT, WireType.VARINT),
|
||||
UINT64("uint64", WireFormat.JavaType.LONG, WireType.VARINT),
|
||||
SINT32("sint32", WireFormat.JavaType.INT, WireType.VARINT),
|
||||
SINT64("sint64", WireFormat.JavaType.LONG, WireType.VARINT),
|
||||
FIXED32("fixed32", WireFormat.JavaType.INT, WireType.FIXED32),
|
||||
FIXED64("fixed64", WireFormat.JavaType.LONG, WireType.FIXED64),
|
||||
SFIXED32("sfixed32", WireFormat.JavaType.INT, WireType.FIXED32),
|
||||
SFIXED64("sfixed64", WireFormat.JavaType.LONG, WireType.FIXED64),
|
||||
BOOL("bool", WireFormat.JavaType.BOOLEAN, WireType.VARINT),
|
||||
ENUM("enum", WireFormat.JavaType.ENUM, WireType.VARINT),
|
||||
STRING("string", WireFormat.JavaType.STRING, WireType.LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean packable() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
BYTES("bytes", WireFormat.JavaType.BYTES, WireType.LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean packable() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
MESSAGE("", WireFormat.JavaType.MESSAGE, WireType.LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean packable() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
OBJECT("OBJECT", WireFormat.JavaType.OBJECT, WireType.LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean packable() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
GROUP("group", WireFormat.JavaType.MESSAGE, WireType.START_GROUP) {
|
||||
@Override
|
||||
public boolean packable() {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
MAP("", WireFormat.JavaType.MAP, WireType.LENGTH_DELIMITED) {
|
||||
@Override
|
||||
public boolean packable() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private final String value;
|
||||
private final WireFormat.JavaType javaType;
|
||||
private final WireType wireType;
|
||||
|
||||
Type(String value, WireFormat.JavaType javaType, WireType wireType) {
|
||||
this.value = value;
|
||||
this.javaType = javaType;
|
||||
this.wireType = wireType;
|
||||
}
|
||||
|
||||
public WireFormat.JavaType javaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
public WireType wireType() {
|
||||
return wireType;
|
||||
}
|
||||
|
||||
public String value() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public boolean packable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性的规则
|
||||
*/
|
||||
private Cardinality cardinality;
|
||||
/**
|
||||
* 消息属性名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 消息属性值的类型
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 消息属性值类型的字符串
|
||||
*/
|
||||
protected String typeString;
|
||||
/**
|
||||
* 属性的顺序标记一个消息内不允许重复
|
||||
*/
|
||||
private int tag;
|
||||
/**
|
||||
* 消息属性默认值
|
||||
*/
|
||||
private String defaultValue;
|
||||
/**
|
||||
* repeated的属性是否对包含的对象列表打包
|
||||
*/
|
||||
private List<Option> options;
|
||||
/**
|
||||
* 属性是否已经被标示为过时的
|
||||
*/
|
||||
private Boolean deprecated;
|
||||
/**
|
||||
* 消息属性的注释信息
|
||||
*/
|
||||
private Comment comment;
|
||||
|
||||
public String getTypeString() {
|
||||
return this.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性的规则
|
||||
*
|
||||
* @return the cardinality
|
||||
*/
|
||||
public Cardinality getCardinality() {
|
||||
return cardinality;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性的规则
|
||||
*
|
||||
* @param cardinality the cardinality to set
|
||||
* @return
|
||||
*/
|
||||
public Field setCardinality(Cardinality cardinality) {
|
||||
this.cardinality = cardinality;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性名称
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性名称
|
||||
*
|
||||
* @param name the name to set
|
||||
* @return
|
||||
*/
|
||||
public Field setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性值的类型
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性值的类型
|
||||
*
|
||||
* @param type the type to set
|
||||
* @return
|
||||
*/
|
||||
public Field setType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性的顺序标记一个消息内不允许重复
|
||||
*
|
||||
* @return the tag
|
||||
*/
|
||||
public int getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性的顺序标记一个消息内不允许重复
|
||||
*
|
||||
* @param tag the tag to set
|
||||
* @return
|
||||
*/
|
||||
public Field setTag(int tag) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性默认值
|
||||
*
|
||||
* @return the defaultValue
|
||||
*/
|
||||
public String getDefaultValue() {
|
||||
if (defaultValue == null) {
|
||||
try {
|
||||
Type fieldType = Type.valueOf(type.toUpperCase(Locale.ENGLISH));
|
||||
if (fieldType.javaType() != null && fieldType.javaType().defaultValue() != null) {
|
||||
return String.valueOf(fieldType.javaType().defaultValue());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
}
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性默认值
|
||||
*
|
||||
* @param defaultValue the defaultValue to set
|
||||
* @return
|
||||
*/
|
||||
public Field setDefaultValue(String defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* repeated的属性是否对包含的对象列表打包
|
||||
*
|
||||
* @return the options
|
||||
*/
|
||||
public List<Option> getOptions() {
|
||||
if (options == null) {
|
||||
options = new ArrayList<>();
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* repeated的属性是否对包含的对象列表打包
|
||||
*
|
||||
* @param options the options to set
|
||||
* @return
|
||||
*/
|
||||
public Field setOptions(List<Option> options) {
|
||||
if (options instanceof ArrayList) {
|
||||
this.options = options;
|
||||
} else {
|
||||
getOptions().addAll(options);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性是否已经被标示为过时的
|
||||
*
|
||||
* @return the deprecated
|
||||
*/
|
||||
public Boolean getDeprecated() {
|
||||
if (deprecated == null) {
|
||||
for (Option option : getOptions()) {
|
||||
if ("deprecated".equals(option.getName())) {
|
||||
return Option.getBoolean(option.getValue());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return deprecated;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性是否已经被标示为过时的
|
||||
*
|
||||
* @param deprecated the deprecated to set
|
||||
* @return
|
||||
*/
|
||||
public Field setDeprecated(Boolean deprecated) {
|
||||
this.deprecated = deprecated;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性的注释信息
|
||||
*
|
||||
* @return the comment
|
||||
*/
|
||||
public Comment getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息属性的注释信息
|
||||
*
|
||||
* @param comment the comment to set
|
||||
* @return
|
||||
*/
|
||||
public Field setComment(Comment comment) {
|
||||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
/**
|
||||
* protocol buffer中Map的Field的结构体定义
|
||||
*/
|
||||
public class MapField extends Field {
|
||||
|
||||
private Type key;
|
||||
private String value;
|
||||
|
||||
@Override
|
||||
public String getTypeString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String keyStr = "";
|
||||
if (getKey() != null) {
|
||||
keyStr = getKey().value();
|
||||
}
|
||||
sb.append("map<").append(keyStr).append(", ");
|
||||
sb.append(getValue()).append(">");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the key
|
||||
*/
|
||||
public Type getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key the key to set
|
||||
* @return
|
||||
*/
|
||||
public MapField setKey(Type key) {
|
||||
this.key = key;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value the value to set
|
||||
* @return
|
||||
*/
|
||||
public MapField setValue(String value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 按名称预留的结构定义
|
||||
*/
|
||||
public class NameReserved extends Reserved {
|
||||
|
||||
/**
|
||||
* 消息保留的属性名称列表
|
||||
*/
|
||||
private List<String> fieldNames;
|
||||
|
||||
public List<String> getFieldNames() {
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
public NameReserved setFieldNames(List<String> names) {
|
||||
this.fieldNames = names;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Oneof结构体定义,oneof定义几个属性必须有一个赋值的功能
|
||||
*/
|
||||
public class Oneof {
|
||||
/**
|
||||
* Oneof标示的名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* Oneof包含的属性列表
|
||||
*/
|
||||
private List<Field> fields;
|
||||
/**
|
||||
* Oneof的注释
|
||||
*/
|
||||
private Comment comment;
|
||||
|
||||
public Oneof setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Oneof setComment(Comment comment) {
|
||||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Comment getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void addField(Field field) {
|
||||
if (getFields() == null) {
|
||||
setFields(new ArrayList<>());
|
||||
}
|
||||
getFields().add(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Oneof包含的属性列表
|
||||
*
|
||||
* @return the fields
|
||||
*/
|
||||
public List<Field> getFields() {
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Oneof包含的属性列表
|
||||
*
|
||||
* @param fields the fields to set
|
||||
*/
|
||||
public void setFields(List<Field> fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
/**
|
||||
* protocol buffer协议的Option的数据类型定义
|
||||
*/
|
||||
public class Option {
|
||||
|
||||
/**
|
||||
* 选项名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 选项对应的值
|
||||
*/
|
||||
private String value;
|
||||
|
||||
public Option setValue(String value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public Option setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static boolean getBoolean(String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
return "true".equalsIgnoreCase(value) || "t".equalsIgnoreCase(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* protocol buffer的枚举类型的定义
|
||||
*/
|
||||
public class ProtoEnum {
|
||||
/**
|
||||
* 枚举名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 枚举包含的值的定义
|
||||
*/
|
||||
private List<EnumEntry> entries;
|
||||
/**
|
||||
* 枚举包含的选项列表
|
||||
*/
|
||||
private List<Option> options;
|
||||
|
||||
/**
|
||||
* 枚举项的定义
|
||||
*/
|
||||
public static class EnumEntry {
|
||||
/**
|
||||
* 枚举值定义的名称
|
||||
*/
|
||||
private String label;
|
||||
/**
|
||||
* 枚举定义的值
|
||||
*/
|
||||
private int value;
|
||||
/**
|
||||
* 枚举的选项列表
|
||||
*/
|
||||
private List<Option> options;
|
||||
/**
|
||||
* 枚举值的注释
|
||||
*/
|
||||
private Comment comment;
|
||||
|
||||
/**
|
||||
* 枚举值定义的名称
|
||||
*
|
||||
* @return the label
|
||||
*/
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举值定义的名称
|
||||
*
|
||||
* @param label the label to set
|
||||
* @return
|
||||
*/
|
||||
public EnumEntry setLabel(String label) {
|
||||
this.label = label;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举定义的值
|
||||
*
|
||||
* @return the value
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举定义的值
|
||||
*
|
||||
* @param value the value to set
|
||||
* @return
|
||||
*/
|
||||
public EnumEntry setValue(int value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举的选项列表
|
||||
*
|
||||
* @return the options
|
||||
*/
|
||||
public List<Option> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举的选项列表
|
||||
*
|
||||
* @param options the options to set
|
||||
* @return
|
||||
*/
|
||||
public EnumEntry setOptions(List<Option> options) {
|
||||
this.options = options;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举值的注释
|
||||
*
|
||||
* @return the comment
|
||||
*/
|
||||
public Comment getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举值的注释
|
||||
*
|
||||
* @param comment the comment to set
|
||||
* @return
|
||||
*/
|
||||
public EnumEntry setComment(Comment comment) {
|
||||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举名称
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举名称
|
||||
*
|
||||
* @param name the name to set
|
||||
* @return
|
||||
*/
|
||||
public ProtoEnum setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举包含的值的定义
|
||||
*
|
||||
* @return the entries
|
||||
*/
|
||||
public List<EnumEntry> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举包含的值的定义
|
||||
*
|
||||
* @param entries the entries to set
|
||||
* @return
|
||||
*/
|
||||
public ProtoEnum setEntries(List<EnumEntry> entries) {
|
||||
this.entries = entries;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举包含的选项列表
|
||||
*
|
||||
* @return the options
|
||||
*/
|
||||
public List<Option> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 枚举包含的选项列表
|
||||
*
|
||||
* @param options the options to set
|
||||
* @return
|
||||
*/
|
||||
public ProtoEnum setOptions(List<Option> options) {
|
||||
this.options = options;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* protocol buffer消息体的结构定义
|
||||
*/
|
||||
public class ProtoMessage {
|
||||
/**
|
||||
* 消息的名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 消息包含的Fields列表
|
||||
*/
|
||||
private List<Field> fields;
|
||||
/**
|
||||
* 消息内嵌的Message列表
|
||||
*/
|
||||
private List<ProtoMessage> protoMessages;
|
||||
/**
|
||||
* 保留字段的设置
|
||||
*/
|
||||
private List<Reserved> reserveds;
|
||||
/**
|
||||
* 消息内嵌的扩展的消息列表
|
||||
*/
|
||||
private List<Extend> protoExtends;
|
||||
/**
|
||||
* 消息包含的扩展的列表
|
||||
*/
|
||||
private List<Extensions> extensionses;
|
||||
|
||||
/**
|
||||
* 消息内置的枚举类型
|
||||
*/
|
||||
private List<ProtoEnum> enums;
|
||||
/**
|
||||
* 消息包含的Oneof的列表
|
||||
*/
|
||||
private List<Oneof> oneofs;
|
||||
/**
|
||||
* 消息的备注信息
|
||||
*/
|
||||
private Comment comment;
|
||||
|
||||
public ProtoMessage addMessage(ProtoMessage child) {
|
||||
if (child == null) {
|
||||
return this;
|
||||
}
|
||||
getMessages().add(child);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProtoMessage addField(Field field) {
|
||||
if (field == null) {
|
||||
return this;
|
||||
}
|
||||
getFields().add(field);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProtoMessage addEnum(ProtoEnum protoEnum) {
|
||||
if (protoEnum == null) {
|
||||
return this;
|
||||
}
|
||||
getEnums().add(protoEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProtoMessage addExtensions(Extensions extensions) {
|
||||
if (extensions == null) {
|
||||
return this;
|
||||
}
|
||||
getExtensionses().add(extensions);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProtoMessage addReserved(Reserved reserved) {
|
||||
if (reserved == null) {
|
||||
return this;
|
||||
}
|
||||
getReserveds().add(reserved);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ProtoMessage addOneof(Oneof oneof) {
|
||||
if (oneof == null) {
|
||||
return this;
|
||||
}
|
||||
getOneofs().add(oneof);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息的名称
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息的名称
|
||||
*
|
||||
* @param name the name to set
|
||||
*/
|
||||
public ProtoMessage setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息包含的Fields列表
|
||||
*
|
||||
* @return the fields
|
||||
*/
|
||||
public List<Field> getFields() {
|
||||
if (fields == null) {
|
||||
fields = new ArrayList<>();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息包含的Fields列表
|
||||
*
|
||||
* @param fields the fields to set
|
||||
*/
|
||||
public ProtoMessage setFields(List<Field> fields) {
|
||||
if (fields instanceof ArrayList) {
|
||||
this.fields = fields;
|
||||
} else {
|
||||
this.fields = new ArrayList<>();
|
||||
this.fields.addAll(fields);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内嵌的Message列表
|
||||
*
|
||||
* @return the messages
|
||||
*/
|
||||
public List<ProtoMessage> getMessages() {
|
||||
if (protoMessages == null) {
|
||||
protoMessages = new ArrayList<>();
|
||||
}
|
||||
return protoMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内嵌的Message列表
|
||||
*
|
||||
* @param protoMessages the messages to set
|
||||
*/
|
||||
public ProtoMessage setMessages(List<ProtoMessage> protoMessages) {
|
||||
if (protoMessages instanceof ArrayList) {
|
||||
this.protoMessages = protoMessages;
|
||||
} else {
|
||||
this.protoMessages = new ArrayList<>();
|
||||
this.protoMessages.addAll(protoMessages);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留字段的设置
|
||||
*
|
||||
* @return the reserveds
|
||||
*/
|
||||
public List<Reserved> getReserveds() {
|
||||
if (reserveds == null) {
|
||||
reserveds = new ArrayList<>();
|
||||
}
|
||||
return reserveds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留字段的设置
|
||||
*
|
||||
* @param reserveds the reserveds to set
|
||||
*/
|
||||
public ProtoMessage setReserveds(List<Reserved> reserveds) {
|
||||
if (reserveds instanceof ArrayList) {
|
||||
this.reserveds = reserveds;
|
||||
} else {
|
||||
this.reserveds = new ArrayList<>();
|
||||
this.reserveds.addAll(reserveds);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内嵌的扩展的消息列表
|
||||
*
|
||||
* @return the protoExtends
|
||||
*/
|
||||
public List<Extend> getProtoExtends() {
|
||||
if (protoExtends == null) {
|
||||
protoExtends = new ArrayList<>();
|
||||
}
|
||||
return protoExtends;
|
||||
}
|
||||
|
||||
public ProtoMessage addProtoExtends(Extend extend) {
|
||||
if (extend == null) {
|
||||
return this;
|
||||
}
|
||||
getProtoExtends().add(extend);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内嵌的扩展的消息列表
|
||||
*
|
||||
* @param protoExtends the protoExtends to set
|
||||
*/
|
||||
public ProtoMessage setProtoExtends(List<Extend> protoExtends) {
|
||||
this.protoExtends = protoExtends;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息包含的扩展的列表
|
||||
*
|
||||
* @return the extensionses
|
||||
*/
|
||||
public List<Extensions> getExtensionses() {
|
||||
if (extensionses == null) {
|
||||
extensionses = new ArrayList<>();
|
||||
}
|
||||
return extensionses;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息包含的扩展的列表
|
||||
*
|
||||
* @param extensionses the extensionses to set
|
||||
*/
|
||||
public ProtoMessage setExtensionses(List<Extensions> extensionses) {
|
||||
if (extensionses instanceof ArrayList) {
|
||||
this.extensionses = extensionses;
|
||||
} else {
|
||||
this.extensionses = new ArrayList<>();
|
||||
this.extensionses.addAll(extensionses);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内置的枚举类型
|
||||
*
|
||||
* @return the enums
|
||||
*/
|
||||
public List<ProtoEnum> getEnums() {
|
||||
if (enums == null) {
|
||||
enums = new ArrayList<>();
|
||||
}
|
||||
return enums;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内置的枚举类型
|
||||
*
|
||||
* @param enums the enums to set
|
||||
*/
|
||||
public ProtoMessage setEnums(List<ProtoEnum> enums) {
|
||||
if (enums instanceof ArrayList) {
|
||||
this.enums = enums;
|
||||
} else {
|
||||
getEnums().addAll(enums);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息包含的Oneof的列表
|
||||
*
|
||||
* @return the oneofs
|
||||
*/
|
||||
public List<Oneof> getOneofs() {
|
||||
if (oneofs == null) {
|
||||
oneofs = new ArrayList<>();
|
||||
}
|
||||
return oneofs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息包含的Oneof的列表
|
||||
*
|
||||
* @param oneofs the oneofs to set
|
||||
*/
|
||||
public ProtoMessage setOneofs(List<Oneof> oneofs) {
|
||||
if (oneofs instanceof ArrayList) {
|
||||
this.oneofs = oneofs;
|
||||
} else {
|
||||
getOneofs().addAll(oneofs);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息的备注信息
|
||||
*
|
||||
* @return the comment
|
||||
*/
|
||||
public Comment getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息的备注信息
|
||||
*
|
||||
* @param comment the comment to set
|
||||
*/
|
||||
public ProtoMessage setComment(Comment comment) {
|
||||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.TagReserved.StartEnd;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.parser.ProtoParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* protocol buffer中预留信息的结构定义
|
||||
*/
|
||||
public class Reserved {
|
||||
/**
|
||||
* 消息保留Field列表的表达式
|
||||
*/
|
||||
private String expression;
|
||||
/**
|
||||
* 保留Fields设置的注释信息
|
||||
*/
|
||||
private Comment comment;
|
||||
|
||||
public Reserved setExpression(String expression) {
|
||||
this.expression = expression;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
public Reserved setComment(Comment comment) {
|
||||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Comment getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public static Reserved parseReserved(String expression, List<Comment> comments) throws RuntimeException {
|
||||
String exp = expression.trim();
|
||||
if (exp.isEmpty()) {
|
||||
throw new RuntimeException("reserved expression is empty");
|
||||
}
|
||||
Reserved reserved;
|
||||
if (exp.charAt(0) == '\'' || exp.charAt(0) == '"') {
|
||||
reserved = new NameReserved().setFieldNames(readFieldNames(exp));
|
||||
} else {
|
||||
reserved = readRagReserved(exp);
|
||||
}
|
||||
if (!comments.isEmpty()) {
|
||||
reserved.setComment(comments.get(comments.size() - 1));
|
||||
comments.clear();
|
||||
}
|
||||
reserved.setExpression(exp);
|
||||
return reserved;
|
||||
}
|
||||
|
||||
public static TagReserved readRagReserved(String expression) throws RuntimeException {
|
||||
TagReserved reserved = new TagReserved();
|
||||
String[] stags = expression.split(",");
|
||||
List<Integer> tags = new ArrayList<>();
|
||||
List<StartEnd> startEnds = new ArrayList<>();
|
||||
for (String sTag : stags) {
|
||||
int index = sTag.indexOf("to");
|
||||
if (index == -1) {
|
||||
int tag = ProtoParser.parseInt(sTag.trim());
|
||||
tags.add(tag);
|
||||
} else {
|
||||
int start = ProtoParser.parseInt(sTag.substring(0, index).trim());
|
||||
int end;
|
||||
String sEnd = sTag.substring(index + 2).trim();
|
||||
if (!"max".equalsIgnoreCase(sEnd)) {
|
||||
end = ProtoParser.parseInt(sTag.substring(index + 2).trim());
|
||||
} else {
|
||||
end = WireFormat.MAX_TAG_VALUE;
|
||||
}
|
||||
StartEnd se = new StartEnd();
|
||||
se.setStartTag(start).setEndTag(end);
|
||||
startEnds.add(se);
|
||||
}
|
||||
}
|
||||
reserved.setTags(tags);
|
||||
reserved.setStartEnds(startEnds);
|
||||
return reserved;
|
||||
}
|
||||
|
||||
public static List<String> readFieldNames(String exp) throws RuntimeException {
|
||||
ParseFieldNameResult res = readFieldName(exp, 0);
|
||||
char endChar = res.getEndChar();
|
||||
List<String> names = new ArrayList<>();
|
||||
while (endChar != ';') {
|
||||
names.add(res.getName());
|
||||
if (res.getPos() >= exp.length()) {
|
||||
return names;
|
||||
}
|
||||
res.setPos(res.getPos() + 1);
|
||||
trim(exp, res);
|
||||
if (res.getPos() < exp.length()) {
|
||||
res = readFieldName(exp, res.getPos());
|
||||
endChar = res.getEndChar();
|
||||
if (endChar != ',' && endChar != '\'' && endChar != '"') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("reserved not end \";\"");
|
||||
}
|
||||
|
||||
private static ParseFieldNameResult readFieldName(String exp, int pos)
|
||||
throws RuntimeException {
|
||||
ParseFieldNameResult result = new ParseFieldNameResult();
|
||||
result.setPos(pos);
|
||||
trim(exp, result);
|
||||
char startChar = result.getEndChar();
|
||||
if (startChar != '\'' && startChar != '"') {
|
||||
throw new RuntimeException("field name not start with ' or \"");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int start = result.getPos();
|
||||
char c;
|
||||
for (int i = start + 1; i < exp.length(); i++) {
|
||||
c = exp.charAt(i);
|
||||
if (c == startChar) {
|
||||
if (sb.length() > 0) {
|
||||
result.setPos(i + 1);
|
||||
trim(exp, result);
|
||||
result.setName(sb.toString());
|
||||
return result;
|
||||
} else {
|
||||
result.setName(sb.toString());
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void trim(String exp, final ParseFieldNameResult result) {
|
||||
int pos = result.getPos();
|
||||
char c;
|
||||
for (int i = pos; i < exp.length(); i++) {
|
||||
c = exp.charAt(i);
|
||||
if (c != ' ' && c != '\t') {
|
||||
result.setPos(i);
|
||||
result.setEndChar(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ParseFieldNameResult {
|
||||
private String name;
|
||||
private int pos;
|
||||
private char endChar;
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public ParseFieldNameResult setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the pos
|
||||
*/
|
||||
public int getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pos the pos to set
|
||||
*/
|
||||
public ParseFieldNameResult setPos(int pos) {
|
||||
this.pos = pos;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the endChar
|
||||
*/
|
||||
public char getEndChar() {
|
||||
return endChar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endChar the endChar to set
|
||||
*/
|
||||
public ParseFieldNameResult setEndChar(char endChar) {
|
||||
this.endChar = endChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
/**
|
||||
* protocol buffer的协议版本
|
||||
*/
|
||||
public enum Syntax {
|
||||
|
||||
PROTO_2("proto2"),
|
||||
PROTO_3("proto3");
|
||||
|
||||
private final String value;
|
||||
|
||||
Syntax(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static Syntax fromValue(String value) {
|
||||
switch (value) {
|
||||
case "proto2":
|
||||
return Syntax.PROTO_2;
|
||||
case "proto3":
|
||||
return Syntax.PROTO_3;
|
||||
default:
|
||||
throw new IllegalArgumentException("no enum value Syntax " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 按Tag的编号预留的结构定义
|
||||
*/
|
||||
public class TagReserved extends Reserved {
|
||||
/**
|
||||
* 消息保留的tag列表
|
||||
*/
|
||||
private List<Integer> tags;
|
||||
/**
|
||||
* 保留tag的开始和结束范围列表
|
||||
*/
|
||||
private List<StartEnd> startEnds;
|
||||
|
||||
|
||||
/**
|
||||
* 消息保留的tag列表
|
||||
*
|
||||
* @return the tags
|
||||
*/
|
||||
public List<Integer> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息保留的tag列表
|
||||
*
|
||||
* @param tags the tags to set
|
||||
* @return
|
||||
*/
|
||||
public TagReserved setTags(List<Integer> tags) {
|
||||
this.tags = tags;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留tag的开始和结束范围列表
|
||||
*
|
||||
* @return the startEnds
|
||||
*/
|
||||
public List<StartEnd> getStartEnds() {
|
||||
return startEnds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保留tag的开始和结束范围列表
|
||||
*
|
||||
* @param startEnds the startEnds to set
|
||||
* @return
|
||||
*/
|
||||
public TagReserved setStartEnds(List<StartEnd> startEnds) {
|
||||
this.startEnds = startEnds;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class StartEnd {
|
||||
private int startTag;
|
||||
private int endTag;
|
||||
|
||||
/**
|
||||
* @return the startTag
|
||||
*/
|
||||
public int getStartTag() {
|
||||
return startTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param startTag the startTag to set
|
||||
* @return
|
||||
*/
|
||||
public StartEnd setStartTag(int startTag) {
|
||||
this.startTag = startTag;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the endTag
|
||||
*/
|
||||
public int getEndTag() {
|
||||
return endTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param endTag the endTag to set
|
||||
* @return
|
||||
*/
|
||||
public StartEnd setEndTag(int endTag) {
|
||||
this.endTag = endTag;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
/**
|
||||
* 协议格式定义相关的常量等
|
||||
*/
|
||||
public class WireFormat {
|
||||
|
||||
private WireFormat() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 定长32位占用的字节长度
|
||||
*/
|
||||
public static final int FIXED_32_SIZE = 4;
|
||||
/**
|
||||
* 定长64位占用的字节长度
|
||||
*/
|
||||
public static final int FIXED_64_SIZE = 8;
|
||||
/**
|
||||
* 变长整型数据最大査勇的字节数
|
||||
*/
|
||||
public static final int MAX_VARINT_SIZE = 5;
|
||||
/**
|
||||
* 定长长整型最大占用的字节数
|
||||
*/
|
||||
public static final int MAX_VARLONG_SIZE = 10;
|
||||
/**
|
||||
* 最小的Tag值
|
||||
*/
|
||||
public static final int MIN_TAG_VALUE = 1;
|
||||
/**
|
||||
* 最大的Tag值
|
||||
*/
|
||||
public static final int MAX_TAG_VALUE = (1 << 29) - 1; // 536,870,911
|
||||
/**
|
||||
* 系统预留Tag的开始值
|
||||
*/
|
||||
public static final int RESERVED_TAG_VALUE_START = 19000;
|
||||
/**
|
||||
* 系统预留Tag的结束值
|
||||
*/
|
||||
public static final int RESERVED_TAG_VALUE_END = 19999;
|
||||
/**
|
||||
* Tag的数据类型占用的bit个数
|
||||
*/
|
||||
static final int TAG_TYPE_BITS = 3;
|
||||
/**
|
||||
* Tag类型的掩码
|
||||
*/
|
||||
static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
|
||||
/**
|
||||
* 空的byte数组
|
||||
*/
|
||||
static final byte[] EMPTY_BYTES = new byte[0];
|
||||
|
||||
/**
|
||||
* Tag值是否符合规则
|
||||
*
|
||||
* @param tag 给定的Tag值
|
||||
* @return 是否符合规则
|
||||
*/
|
||||
public static boolean isValidTag(int tag) {
|
||||
return (tag >= MIN_TAG_VALUE && tag < RESERVED_TAG_VALUE_START)
|
||||
|| (tag > RESERVED_TAG_VALUE_END && tag <= MAX_TAG_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从int值盅获取该Tag的数据类型的int值
|
||||
*
|
||||
* @param tag 给定的int值
|
||||
* @return
|
||||
*/
|
||||
public static int getTagWireType(final int tag) {
|
||||
return tag & TAG_TYPE_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取给定的int值中Tag的值
|
||||
*
|
||||
* @param tag 解码出的tag的int值
|
||||
* @return
|
||||
*/
|
||||
public static int getTagFieldNumber(final int tag) {
|
||||
return tag >>> TAG_TYPE_BITS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据属性的Tag值,以及数据类型,获取一个编码后的int值
|
||||
*
|
||||
* @param tagNum tag的编号
|
||||
* @param wireType 数据类型
|
||||
* @return
|
||||
*/
|
||||
public static int makeTag(final int tagNum, final WireType wireType) {
|
||||
return (tagNum << TAG_TYPE_BITS) | wireType.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* java的数据类型和protocol buffer的数据类型的对应关系以及默认值
|
||||
*/
|
||||
public enum JavaType {
|
||||
INT("int", "Integer", 0),
|
||||
LONG("long", "Long", 0L),
|
||||
FLOAT("float", "Float", 0F),
|
||||
DOUBLE("double", "Double", 0D),
|
||||
BOOLEAN("boolean", "Boolean", false),
|
||||
STRING("String", "String", ""),
|
||||
BYTES("byte[]", "byte[]", EMPTY_BYTES),
|
||||
ENUM("enum", "enum", null),
|
||||
MESSAGE("", "", null),
|
||||
OBJECT("Object", "Object", null),
|
||||
MAP("Map", "Map", null);
|
||||
|
||||
JavaType(final String typeString, final String boxedType, final Object defaultValue) {
|
||||
this.typeString = typeString;
|
||||
this.boxedType = boxedType;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public String getTypeString() {
|
||||
return this.typeString;
|
||||
}
|
||||
|
||||
/**
|
||||
* The default value for fields of this type, if it's a primitive type.
|
||||
*/
|
||||
public Object defaultValue() {
|
||||
return this.defaultValue;
|
||||
}
|
||||
|
||||
public String getBoxedType() {
|
||||
return this.boxedType;
|
||||
}
|
||||
|
||||
private final Object defaultValue;
|
||||
private final String typeString;
|
||||
|
||||
private final String boxedType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire;
|
||||
|
||||
/**
|
||||
* protocol buffer的协议数据类型
|
||||
*/
|
||||
public enum WireType {
|
||||
/**
|
||||
* 变长整数
|
||||
*/
|
||||
VARINT(0),
|
||||
/**
|
||||
* 定长64位
|
||||
*/
|
||||
FIXED64(1),
|
||||
/**
|
||||
* 指定长度的编码类型
|
||||
*/
|
||||
LENGTH_DELIMITED(2),
|
||||
/**
|
||||
* 组开始标记
|
||||
*/
|
||||
START_GROUP(3),
|
||||
/**
|
||||
* 组结束标记
|
||||
*/
|
||||
END_GROUP(4),
|
||||
/**
|
||||
* 定长32位
|
||||
*/
|
||||
FIXED32(5),
|
||||
/**
|
||||
* OBJECT类型,可以包含任何类型的数据由OBJECT编解码器进行编解码
|
||||
*/
|
||||
OBJECT(6);
|
||||
|
||||
WireType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private final int value;
|
||||
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static WireType fromValue(int value) {
|
||||
switch (value) {
|
||||
case 0:
|
||||
return VARINT;
|
||||
case 1:
|
||||
return FIXED64;
|
||||
case 2:
|
||||
return LENGTH_DELIMITED;
|
||||
case 3:
|
||||
return START_GROUP;
|
||||
case 4:
|
||||
return END_GROUP;
|
||||
case 5:
|
||||
return FIXED32;
|
||||
case 6:
|
||||
return OBJECT;
|
||||
default:
|
||||
throw new IllegalArgumentException("no enum value WireType " + value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.wire.parser;
|
||||
|
||||
import com.zfoo.protocol.collection.CollectionUtils;
|
||||
import com.zfoo.protocol.serializer.protobuf.wire.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* proto文件的结构定义
|
||||
*/
|
||||
public class Proto {
|
||||
|
||||
/**
|
||||
* Proto描述文件的名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* Proto的可选信息
|
||||
*/
|
||||
private List<Option> options = new ArrayList<>();
|
||||
/**
|
||||
* 文档版本没有指定默认为proto2
|
||||
*/
|
||||
private Syntax syntax = Syntax.PROTO_3;
|
||||
/**
|
||||
* proto文件的包名
|
||||
*/
|
||||
private String protoPackage;
|
||||
/**
|
||||
* 定义的消息列表
|
||||
*/
|
||||
private List<ProtoMessage> protoMessages = new ArrayList<>();
|
||||
/**
|
||||
* 文档导入的文件的路径列表
|
||||
*/
|
||||
private List<String> imports = new ArrayList<>();
|
||||
/**
|
||||
* 文档的注释
|
||||
*/
|
||||
private String comment;
|
||||
/**
|
||||
* 消息内置的枚举类型
|
||||
*/
|
||||
private List<ProtoEnum> enums = new ArrayList<>();
|
||||
/**
|
||||
* 消息内嵌的扩展的消息列表
|
||||
*/
|
||||
private List<Extend> protoExtends = new ArrayList<>();
|
||||
/**
|
||||
* proto文件的单行注释列表
|
||||
*/
|
||||
private List<String> comments = new ArrayList<>();
|
||||
/**
|
||||
* 该文件的来源的File对象
|
||||
*/
|
||||
private File file;
|
||||
|
||||
public Proto setSyntax(Syntax syntax) {
|
||||
this.syntax = syntax;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Proto addOption(Option option) {
|
||||
getOptions().add(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Proto addImport(String value) {
|
||||
getImports().add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Proto addMsg(ProtoMessage msg) {
|
||||
getMessages().add(msg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Proto addEnum(ProtoEnum protoEnum) {
|
||||
getEnums().add(protoEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Proto addExtend(Extend extend) {
|
||||
if (extend == null) {
|
||||
return this;
|
||||
}
|
||||
getProtoExtends().add(extend);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proto描述文件的名称
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proto描述文件的名称
|
||||
*
|
||||
* @param name the name to set
|
||||
* @return
|
||||
*/
|
||||
public Proto setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proto的可选信息
|
||||
*
|
||||
* @return the options
|
||||
*/
|
||||
public List<Option> getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档版本没有指定默认为proto2
|
||||
*
|
||||
* @return the syntax
|
||||
*/
|
||||
public Syntax getSyntax() {
|
||||
return syntax;
|
||||
}
|
||||
|
||||
/**
|
||||
* proto文件的包名
|
||||
*
|
||||
* @return the protoPackage
|
||||
*/
|
||||
public String getProtoPackage() {
|
||||
return protoPackage;
|
||||
}
|
||||
|
||||
/**
|
||||
* proto文件的包名
|
||||
*
|
||||
* @param protoPackage the protoPackage to set
|
||||
* @return
|
||||
*/
|
||||
public Proto setProtoPackage(String protoPackage) {
|
||||
this.protoPackage = protoPackage;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定义的消息列表
|
||||
*
|
||||
* @return the messages
|
||||
*/
|
||||
public List<ProtoMessage> getMessages() {
|
||||
return protoMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档导入的文件的路径列表
|
||||
*
|
||||
* @return the imports
|
||||
*/
|
||||
public List<String> getImports() {
|
||||
return imports;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档的注释
|
||||
*
|
||||
* @return the comment
|
||||
*/
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文档的注释
|
||||
*
|
||||
* @param comment the comment to set
|
||||
* @return
|
||||
*/
|
||||
public Proto setComment(String comment) {
|
||||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内置的枚举类型
|
||||
*
|
||||
* @return the enums
|
||||
*/
|
||||
public List<ProtoEnum> getEnums() {
|
||||
return enums;
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息内嵌的扩展的消息列表
|
||||
*
|
||||
* @return the protoExtends
|
||||
*/
|
||||
public List<Extend> getProtoExtends() {
|
||||
return protoExtends;
|
||||
}
|
||||
|
||||
/**
|
||||
* proto文件的单行注释列表
|
||||
*
|
||||
* @param comments the comments to set
|
||||
*/
|
||||
public void addComments(List<String> comments) {
|
||||
if (CollectionUtils.isEmpty(comments)) {
|
||||
return;
|
||||
}
|
||||
this.comments.addAll(comments);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the file
|
||||
*/
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file the file to set
|
||||
*/
|
||||
public void setFile(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
}
|
||||
+1159
File diff suppressed because it is too large.
Load diff
@@ -420,7 +420,7 @@ public abstract class FileUtils {
|
||||
|
||||
|
||||
public static String readFileToString(final File file) {
|
||||
return StringUtils.joinWith(StringUtils.EMPTY, readFileToStringList(file).toArray());
|
||||
return StringUtils.joinWith(LS, readFileToStringList(file).toArray());
|
||||
}
|
||||
|
||||
public static List<String> readFileToStringList(final File file) {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2021 The edap Project
|
||||
*
|
||||
* 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.protobuf;
|
||||
|
||||
import com.zfoo.protocol.serializer.protobuf.GeneratePbUtils;
|
||||
import com.zfoo.protocol.serializer.protobuf.PbBuildOption;
|
||||
import com.zfoo.protocol.util.ThreadUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class AllTypeBuilderTest {
|
||||
|
||||
@Test
|
||||
public void testAllTypeTest() {
|
||||
var buildOption = new PbBuildOption();
|
||||
buildOption.setProtoPath("D:\\github\\zfoo\\protocol\\src\\test\\resources\\proto");
|
||||
// buildOption.setProtoPath("D:\\github\\zoo\\app\\zgame\\zgame-common\\src\\main\\resources\\proto");
|
||||
buildOption.setOutputPath("D:\\github\\zfoo\\protocol\\src\\test\\tmpsrc/");
|
||||
|
||||
GeneratePbUtils.create(buildOption);
|
||||
ThreadUtils.sleep(1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
syntax = "proto3";
|
||||
|
||||
|
||||
package test.message;
|
||||
|
||||
import "one_enum.proto";
|
||||
import "one_map.proto";
|
||||
import "one_message.proto";
|
||||
option java_package = "io.edap.protobuf.test.message.v3";
|
||||
//option java_outer_classname = "MessageOuter";
|
||||
|
||||
message AllType {
|
||||
bool field1 = 1;
|
||||
bytes field2 = 2;
|
||||
double field3 = 3;
|
||||
Corpus field4 = 4;
|
||||
fixed32 field5 = 5;
|
||||
fixed64 field6 = 6;
|
||||
float field7 = 7;
|
||||
int32 field8 = 8;
|
||||
int64 field9 = 9;
|
||||
map<string, Project> field10 = 10;
|
||||
Proj field11 = 11;
|
||||
sfixed32 field12 = 12;
|
||||
sfixed64 field13 = 13;
|
||||
sint32 field14 = 14;
|
||||
sint64 field15 = 15;
|
||||
string field16 = 16;
|
||||
uint32 field17 = 17;
|
||||
uint64 field18 = 18;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
syntax = "proto3";
|
||||
|
||||
|
||||
package test.message;
|
||||
|
||||
option java_package = "io.edap.protobuf.test.message.v3";
|
||||
|
||||
message OneEnum {
|
||||
Corpus corpus = 1;
|
||||
}
|
||||
|
||||
|
||||
enum Corpus {
|
||||
UNIVERSAL = 0;
|
||||
WEB = 1;
|
||||
IMAGES = 2;
|
||||
LOCAL = 3;
|
||||
NEWS = 4;
|
||||
PRODUCTS = 5;
|
||||
VIDEO = 6;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
syntax = "proto3";
|
||||
|
||||
|
||||
package test.message;
|
||||
|
||||
option java_package = "io.edap.protobuf.test.message.v3";
|
||||
|
||||
message OneMap {
|
||||
map<string, Project> value = 1;
|
||||
}
|
||||
|
||||
message Project {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
string repoPath = 3;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
syntax = "proto3";
|
||||
|
||||
|
||||
package test.message;
|
||||
|
||||
option java_package = "io.edap.protobuf.test.message.v3";
|
||||
|
||||
message OneMessage {
|
||||
Proj value = 1;
|
||||
}
|
||||
|
||||
message Proj {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
string repoPath = 3;
|
||||
//zzzzzzz
|
||||
repeated int32 a = 4;//rrrrrrrrrrrrrrrrrrrrrrr
|
||||
}
|
||||
Reference in new issue
Block a user