Jprotobuf Generate .proto
Introduction
Jprotobuf provides a simplified way to use Google Protocol Buffers with equivalent performance. With jprotobuf, you do not need to manually write proto file syntax. You can define fields directly with Java annotations.
This module enhances jprotobuf in the following ways:
- Multiple objects can be generated into the same
.protofile. - You can omit jprotobuf field annotations for further simplification.
How to Install
This module is optional. Add it to pom.xml when needed.
see https://central.sonatype.com/artifact/com.iohao.net/extension-jprotobuf
<dependency>
<groupId>com.iohao.net</groupId>
<artifactId>extension-jprotobuf</artifactId>
<version>${ionet.version}</version>
</dependency>
How to Generate .proto
Via Utility Class
Add the package names to scan. The default output directory for .proto is target/proto.
void test1() {
GenerateFileKit.generate("com.iohao.example.sdk.logic.data");
}
Via ProtoGenerateFile
- code 3: specify the proto output directory. If omitted, default is
target/proto. - code 4: add package names to scan.
- code 6: generate
.protofiles.
void test2() {
var protoGenerateFile = new ProtoGenerateFile()
.setGenerateFolder(path)
.addProtoPackage("com.iohao.example.sdk.logic.data");
protoGenerateFile.generate();
}
Multi-Module On-Demand Generation
- code 6: specify the proto output directory. If omitted, default is
target/proto. - code 7~9: add package names to scan.
- code 10: generate
.protofiles.
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 Annotation
ProtoFileMerge has two attributes:
- fileName: specifies the
.protofile name. - filePackage: specifies the
.protopackage name.
You must add this annotation on a class to generate it into a .proto file.
Usage Example
Now we define 3 classes (protocol data classes) used for communication between client and server.
Data Protocol Classes
Two required annotations for protocol data classes:
- ProtobufClass: marks a class as a protocol data class.
- ProtoFileMerge: provides metadata required for
.protogeneration.
public interface TempProtoFile {
String fileName = "common.proto";
String filePackage = "pb.common";
}
/**
* MyFood
*/
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
@ProtoFileMerge(fileName = TempProtoFile.fileName, filePackage = TempProtoFile.filePackage)
public class Food {
/** id */
int id;
/** food name */
String foodName;
}
/**
* My Cat
*/
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
@ProtoFileMerge(fileName = TempProtoFile.fileName, filePackage = TempProtoFile.filePackage)
public class Cat {
/** id */
int id;
/** cat name */
String catName;
/** the food */
Food food;
/** the animalType */
AnimalTypeEnum animalType;
}
@ProtobufClass
@ProtoFileMerge(fileName = TempProtoFile.fileName, filePackage = TempProtoFile.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;
}
}
Generated .proto File
Protocol data will be generated into common.proto as shown below.
You can see that structures in common.proto contain comments.
These comments come from the Java classes above, so code and documentation stay aligned.
syntax = "proto3";
package pb.common;
// TestAnimalTypeEnum
enum AnimalTypeEnum {
// the cat
cat = 0;
// the tiger
tiger = 10;
}
// MyCat
message Cat {
// id
int32 id = 1;
// cat name
string cat_name = 2;
// the food
Food food = 3;
// the animalType
AnimalTypeEnum animal_type = 4;
}
// MyFood
message Food {
// id
int32 id = 1;
// food name
string food_name = 2;
}
Enum
Default Enum Values
When using enums, values start from 0 by default.
/**
* The AnimalType
*/
@ProtobufClass
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public enum AnimalType {
/** the bird */
BIRD,
/** the cat */
CAT;
}
/**
* The Animal
*/
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
@ProtoFileMerge(fileName = MyProtoFile.fileName, filePackage = MyProtoFile.filePackage)
public class Animal {
/** id */
int id;
/** AnimalType */
AnimalType animalType;
}
syntax = "proto3";
package common;
// The Animal
message Animal {
// id
int32 id = 1;
// AnimalType
AnimalType animal_type = 2;
}
// The AnimalType
enum AnimalType {
// the bird
BIRD = 0;
// the cat
CAT = 1;
}
Custom Enum Values
When using enums, custom values require implementing the EnumReadable interface.
@ProtobufClass
@ProtoFileMerge(fileName = TempProtoFile.fileName, filePackage = TempProtoFile.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;
}
}
syntax = "proto3";
package common;
// TestAnimalTypeEnum
enum AnimalTypeEnum {
// the cat
cat = 0;
// the tiger
tiger = 10;
}
Field Naming Style
Generated .proto field names use UnderScoreCase by default.
syntax = "proto3";
package common;
// food
message Food {
// id
sint32 id = 1;
// food name
string food_name = 2;
}
Developers can also customize the naming style, for example to keep the same names as Java fields:
ProtoGenerateSetting.setFieldNameFunction(FieldNameGenerate::getFieldName);
syntax = "proto3";
// MyFood
message Food {
// id
int32 id = 1;
// food name
string foodName = 2;
}
Notes and Considerations
Comments support single-line style only, so describe each field clearly in one sentence.
public class Animal {
/** id */
int id;
/** the animalType */
AnimalType animalType;
}
Required annotations for protocol data classes:
- ProtobufClass: marks a class as a protocol data class.
- ProtoFileMerge: provides metadata required for
.protogeneration.
@ProtobufClass
@ProtoFileMerge(fileName = TempProtoFile.fileName, filePackage = TempProtoFile.filePackage)
public class Food {
...
}
Supported types: see https://github.com/jhunters/jprotobuf/blob/master/Document.md