Protobuf 序列化 反序列化
操作步骤
- 在.proto文件中定义消息格式。
- 使用协议缓冲区编译器。
- 使用Java协议缓冲区API来写入和读取消息。
.proto 文件
.proto文件以包声明开始(有助于防止不同项目之间的命名冲突)。在Java中,除非明确指定java_package
,否则package
将用作Java包。
java_package
指定生成的类应该使用哪个java包名称。
java_outer_classname
表示该文件的类名。如果您没有显式地给出java_outer_classname,那么使用将文件名转换为大写来生成。例如,默认情况下,“my_proto.proto”会使用“MyProto”作为包装类名称。java_multiple_files=true
选项允许为每个生成的类生成一个单独的.java文件。
消息申明格式如下:
phone.proto
syntax = "proto3";
package pr.iceworld.fernando.protobuf.proto;
option java_package = "pr.iceworld.fernando.protobuf.proto";
//option java_multiple_files = true;
option java_outer_classname = "PhoneProto";
message Phone {
int32 id = 1;
string value = 2;
Brand brand = 3;
}
enum Brand {
APPLE = 0;
SAMSUNG = 1;
HUAWEI = 2;
MI = 3;
reserved 4 to 19;
}
customer.proto
syntax = "proto3";
package pr.iceworld.fernando.protobuf.proto;
option java_package = "pr.iceworld.fernando.protobuf.proto";
//option java_multiple_files = true;
option java_outer_classname = "CustomerProto";
import "phone.proto";
message Customer {
int32 id = 1;
string name = 2;
// enum type
Gender gender = 3;
// embed class
message Address {
int32 id = 1;
string value = 2;
bool default = 3;
}
// array
repeated Address addresses = 4;
Phone phone = 5;
map<string, string> attrs = 6;
}
enum Gender {
MALE = 0;
FEMALE = 1;
}
pom.xml 依赖包
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>1.54.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.54.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.54.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.22.2</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>3.22.2</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.1</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.22.2:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
maven执行操作
生成的CustomerProto.java
代码(片段)如下
package pr.iceworld.fernando.protobuf.proto;
public final class CustomerProto {
private CustomerProto() {}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistryLite registry) {
}
public static void registerAllExtensions(
com.google.protobuf.ExtensionRegistry registry) {
registerAllExtensions(
(com.google.protobuf.ExtensionRegistryLite) registry);
}
/**
* Protobuf enum {@code pr.iceworld.fernando.protobuf.proto.Gender}
*/
public enum Gender
implements com.google.protobuf.ProtocolMessageEnum {
/**
* <code>MALE = 0;</code>
*/
MALE(0),
/**
* <code>FEMALE = 1;</code>
*/
FEMALE(1),
UNRECOGNIZED(-1),
;
// ...
序列化反序列化,同时转换为json
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import java.util.Arrays;
public class MainApp {
public static void main(String[] args) {
// builder for customer
CustomerProto.Customer.Builder customerBuilder = CustomerProto.Customer.newBuilder();
customerBuilder.setId(1);
customerBuilder.setName("fernando");
customerBuilder.setGender(CustomerProto.Gender.MALE);
// builder for address
CustomerProto.Customer.Address.Builder addressBuilder1 =
CustomerProto.Customer.Address.newBuilder();
addressBuilder1.setId(1);
addressBuilder1.setDefault(true);
addressBuilder1.setValue("XXXX AAAA BBBB");
customerBuilder.addAddresses(addressBuilder1);
// builder for address
CustomerProto.Customer.Address.Builder addressBuilder2 =
CustomerProto.Customer.Address.newBuilder();
addressBuilder2.setId(2);
addressBuilder2.setDefault(false);
addressBuilder2.setValue("YYYY CCCCC DDDD");
customerBuilder.addAddresses(addressBuilder2);
// builder for phone
PhoneProto.Phone.Builder phoneBuilder = PhoneProto.Phone.newBuilder();
phoneBuilder.setBrand(PhoneProto.Brand.APPLE);
phoneBuilder.setId(1);
phoneBuilder.setValue("8610000");
customerBuilder.setPhone(phoneBuilder);
// attrs Map<String, String>
customerBuilder.putAttrs("Sports", "Running");
customerBuilder.putAttrs("Food", "Chicken");
CustomerProto.Customer customer = customerBuilder.build();
try {
String toJsonOri = JsonFormat.printer().print(customer);
System.out.println(String.format("json result=%s", toJsonOri));
System.out.println(String.format("json size=%s", toJsonOri.getBytes().length));
// serializable
byte[] bytes4Customer = customer.toByteArray();
System.out.println(String.format("bytes4Customer=%s", Arrays.toString(bytes4Customer)));
System.out.println(String.format("bytes4Customer's length=%s", bytes4Customer.length));
// deserializable
CustomerProto.Customer deCustomer = CustomerProto.Customer.parseFrom(bytes4Customer);
// can change to json format
String toJsonDe = JsonFormat.printer().print(deCustomer);
System.out.println(String.format("json result=%s", toJsonDe));
System.out.println(String.format("json size=%s", toJsonDe.getBytes().length));
} catch (InvalidProtocolBufferException e) {
throw new RuntimeException(e);
}
}
}
输出结果
json result={
"id": 1,
"name": "fernando",
"addresses": [{
"id": 1,
"value": "XXXX AAAA BBBB",
"default": true
}, {
"id": 2,
"value": "YYYY CCCCC DDDD"
}],
"phone": {
"id": 1,
"value": "8610000"
},
"attrs": {
"Sports": "Running",
"Food": "Chicken"
}
}
json size=293
bytes4Customer=[8, 1, 18, 8, 102, 101, 114, 110, 97, 110, 100, 111, 34, 20, 8, 1, 18, 14, 88, 88, 88, 88, 32, 65, 65, 65, 65, 32, 66, 66, 66, 66, 24, 1, 34, 19, 8, 2, 18, 15, 89, 89, 89, 89, 32, 67, 67, 67, 67, 67, 32, 68, 68, 68, 68, 42, 11, 8, 1, 18, 7, 56, 54, 49, 48, 48, 48, 48, 50, 17, 10, 6, 83, 112, 111, 114, 116, 115, 18, 7, 82, 117, 110, 110, 105, 110, 103, 50, 15, 10, 4, 70, 111, 111, 100, 18, 7, 67, 104, 105, 99, 107, 101, 110]
bytes4Customer's length=104
json result={
"id": 1,
"name": "fernando",
"addresses": [{
"id": 1,
"value": "XXXX AAAA BBBB",
"default": true
}, {
"id": 2,
"value": "YYYY CCCCC DDDD"
}],
"phone": {
"id": 1,
"value": "8610000"
},
"attrs": {
"Sports": "Running",
"Food": "Chicken"
}
}
json size=293