版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liuxiao723846/article/details/83182557
本文将介绍用java解析.proto文件。
protobuffer的java库里面有提供可以直接解析.ptoto文件的相关类,并不能像C++那样直接可以解析.proto文件,而本文主要介绍相关解析类如何使用。
1、为什么要解析proto文件结构呢?
如果已知protobuf内容对应的是哪个类对象,则可以直接使用反序列化方法搞定(Xxx.parseFrom(inputStream)由二进制转换,TextFormat.merge(string, xxxBuilder)由文本转换)。而我们经常遇到的情况是,拿到一个被protobuf序列化的二进制内容,但不知道它的类型,无法获得对应的类对象。
这种多见于需要处理各种各样未知的ProtoBuf对象的系统。ProtoBuf提供了动态解析机制来解决这个问题,它要求提供二进制内容的基础上,再提供对应类的Descriptor对象,在解析时通过DynamicMessage类的成员方法来获得对象结果。
2、方法:
不能直接用protobuf提供的库来解析.proto文件,但是可以用它提供的解析的.desc文件来获取.proto文件信息。所以要先调用如下命令生成desc文件:
protoc --descriptor_set_out=XXX.description ./XXX.proto --proto_path=.
通过FileDescriptorSet这个类来解析了,然后获得FileDescriptor.
3、示例:
1)pb结构:
option java_package="com.liulei.cinema";
enum MovieType{
CHILDREN=1;
ADULT=2;
NORMAL=3;
OHTER=4;
}
enum Gender{
MAN=1;
WOMAN=2;
OTHER=3;
}
message Movie{
required string name=1;
required MovieType type=2;
optional int32 releaseTimeStamp=3;
optional string description=4;
}
message Customer{
required string name=1;
optional Gender gender=2;
optional int32 birthdayTimeStamp=3;
}
message Ticket{
required int32 id=1;
required Movie movie=2;
required Customer customer=3;
}
2)通过如下命令生成对应的java文件:
>protoc --java_out=./ cinema.proto
3)将java文件导入到工程,在工程中示例话pb对象,然后再通过生成descriptor文件,利用DynamicMessage类来反序列:
public static void main( String[] args ) {
//实例化pb对象
Cinema.Movie.Builder movieBuilder = Cinema.Movie.newBuilder();
movieBuilder.setName("The Shining");
movieBuilder.setType(Cinema.MovieType.ADULT);
movieBuilder.setReleaseTimeStamp(327859200);
System.out.println("Dynamic Message Parse by proto file");
try {
byte[] buffer3 = new byte[movieBuilder.build().getSerializedSize()];
CodedOutputStream codedOutputStream3 = CodedOutputStream.newInstance(buffer3);
try {
movieBuilder.build().writeTo(codedOutputStream3);
System.out.println(buffer3);
} catch (IOException e) {
e.printStackTrace();
}
//生成descriptor文件
String protocCMD = "protoc --descriptor_set_out=cinema.description ./cinema.proto --proto_path=.";
Process process = Runtime.getRuntime().exec(protocCMD);
process.waitFor();
int exitValue = process.exitValue();
if (exitValue != 0) {
System.out.println("protoc execute failed");
return;
}
//反序列化
Descriptors.Descriptor pbDescritpor = null;
DescriptorProtos.FileDescriptorSet descriptorSet = DescriptorProtos.FileDescriptorSet.parseFrom(new FileInputStream("./cinema.description"));
for (DescriptorProtos.FileDescriptorProto fdp : descriptorSet.getFileList()) {
Descriptors.FileDescriptor fileDescriptor = Descriptors.FileDescriptor.buildFrom(fdp, new Descriptors.FileDescriptor[]{});
for (Descriptors.Descriptor descriptor : fileDescriptor.getMessageTypes()) {
if (descriptor.getName().equals("Movie")) {
System.out.println("Movie descriptor found");
pbDescritpor = descriptor;
break;
}
}
}
if (pbDescritpor == null) {
System.out.println("No matched descriptor");
return;
}
DynamicMessage.Builder pbBuilder = DynamicMessage.newBuilder(pbDescritpor);
Message pbMessage = pbBuilder.mergeFrom(buffer3).build();
System.out.println(pbMessage);
} catch (Exception e) {
System.out.println("Exception");
e.printStackTrace();
}
}