Jprotobuf 生成 .proto
介绍
Jprotobuf 是对 Google Protocol Buffers 的简化使用,性能同等。 使用 jprotobuf 可以无需再去了解 proto 文件操作与语法,可以直接使用 java 注解定义字段类型。
Light-jprotobuf 是对 jprotobuf 的增强,如下
- 可以让多个对象生成在同一个 .proto 文件中。
- 可以不用写 jprotobuf 字段注解,进一步简化 jprotobuf 的使用。
如何安装
由于 light-jprotobuf 是单独的、按需选择的功能模块,使用时需要在 pom.xml 中引入
see https://central.sonatype.com/artifact/com.iohao.game/light-jprotobuf
<dependency>
<groupId>com.iohao.game</groupId>
<artifactId>light-jprotobuf</artifactId>
<version>${ioGame.version}</version>
</dependency>
如何生成 .proto
通过工具类
添加需要扫描的包名,.proto 默认生成的目录为 target/proto
void test1() {
GenerateFileKit.generate("com.iohao.example.sdk.logic.data");
}
通过 ProtoGenerateFile
- code 3,指定 proto 生成的目录。如果不指定,默认生成的目录为 target/proto
- code 4,添加需要扫描的包名
- code 6,生成 .proto 文件
void test2() {
var protoGenerateFile = new ProtoGenerateFile()
.setGenerateFolder(path)
.addProtoPackage("com.iohao.example.sdk.logic.data");
protoGenerateFile.generate();
}
多模块按需生成
- code 6,指定 proto 生成的目录。如果不指定,默认生成的目录为 target/proto
- code 7~9,添加需要扫描的包名
- code 10,生成 .proto 文件
void test2() {
String generateFolder = "/Users/join/gitme/game/MyGames/proto";
var protoPackageList = List.of("com.iohao.happy.robot", "com.iohao.happy.email");
var protoGenerateFile = new ProtoGenerateFile()
.setGenerateFolder(generateFolder)
.addProtoPackage(protoPackageList)
.addProtoPackage("com.iohao.happy.common.provide.proto");
protoGenerateFile.generate();
}
ProtoFileMerge 注解
在 ProtoFileMerge 注解有两个属性
- fileName,指定 .proto 的文件名
- filePackage,指定 .proto 的包名
必须在类上添加此注解才能将类生成到 .proto 文件中。
使用示例
现在,我们定义 3 个类,这些类也称为协议数据类,用于请求端与服务器的通信。
数据协议类
协议数据类必须的两个注解
- ProtobufClass,标记类是一个协议数据类。
- ProtoFileMerge,生成 .proto 时需要的信息。
public interface MyProtoFile {
String fileName = "common.proto";
String filePackage = "common";
}
/**
* 猫
*/
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public class Cat {
/** id */
int id;
/** 猫的名字 */
String catName;
/** 食物 map */
Map<Integer, Integer> foodMap;
/** 道具 id 列表 */
List<Long> propIdList;
}
/**
* 食物
*/
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public class Food {
/** id */
int id;
/** 食物名 */
String foodName;
}
/**
* 老虎
*/
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public class Tiger {
/** id */
int id;
/** 食物 */
Food food;
}
生成的 .proto 文件
协议数据将会生成到 common.proto 文件中,内容如下。
细心的朋友可以看见,common.proto 文件中的结构体包含了注释。 这些注释来源于我们上面定义的 java 类,这样做到了代码即注释。
syntax = "proto3";
package common;
// 猫
message Cat {
// id
sint32 id = 1;
// 猫的名字
string cat_name = 2;
// 食物 map
map<sint32,sint32> food_map = 3;
// 道具 id 列表
repeated sint64 prop_id_list = 4;
}
// 食物
message Food {
// id
sint32 id = 1;
// 食物名
string food_name = 2;
}
// 老虎
message Tiger {
// id
sint32 id = 1;
// 食物
Food food = 2;
}
枚举
从 17.1.38 版本开始,此模块提供了枚举的支持,由 miaozhiyan 贡献的 #79 。
/**
* 动物类型
*/
@ProtobufClass
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public enum AnimalType {
/** 鸟 */
BIRD,
/** 猫 */
CAT;
}
/**
* 动物
*/
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public class Animal {
/** id */
int id;
/** 动物类型 - 枚举测试 */
AnimalType animalType;
}
common.proto
syntax = "proto3";
package common;
// 动物
message Animal {
// id
int32 id = 1;
// 动物类型 - 枚举测试
AnimalType animal_type = 2;
}
// 动物类型
enum AnimalType {
// 鸟
BIRD = 0;
// 猫
CAT = 1;
}
枚举自定义值
从 ioGame21.23 版本开始支持自定义枚举值,see #414
@ProtobufClass
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public enum AnimalTypeEnum implements EnumReadable {
/** the cat */
cat(0),
/** the tiger */
tiger(10),
;
final int value;
AnimalTypeEnum(int value) {
this.value = value;
}
@Override
public int value() {
return this.value;
}
}
common.proto
syntax = "proto3";
package common;
// TestAnimalTypeEnum
enum AnimalTypeEnum {
// the cat
cat = 0;
// the tiger
tiger = 10;
}
字段命名风格
生成的 .proto 字段名默认使用 UnderScoreCase 风格。
syntax = "proto3";
package common;
// 食物
message Food {
// id
sint32 id = 1;
// 食物名
string food_name = 2;
}
开发者也可以自定义生成的风格,如下设置与类属性同名
ProtoGenerateSetting.setFieldNameFunction(FieldNameGenerate::getFieldName);
syntax = "proto3";
package common;
// 食物
message Food {
// id
sint32 id = 1;
// 食物名
string foodName = 2;
}
注意事项
只支持单行注释
注释只支持单行,所以,请用一句话将事情描述清楚。
public class Animal {
/** id */
int id;
/** 动物类型 - 枚举测试 */
AnimalType animalType;
}
必须添加的注解
协议数据类必须的两个注解
- ProtobufClass,标记类是一个协议数据类。
- ProtoFileMerge,生成 .proto 时需要的信息。
@ProtobufClass
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public class Food {
int id;
String foodName;
}
支持的类型
see https://github.com/jhunters/jprotobuf/blob/master/Document.md