protobuf反射

版权声明:本文为博主原创文章,未经博主允许不得转载。 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();
         }
     }

猜你喜欢

转载自blog.csdn.net/liuxiao723846/article/details/83182557
今日推荐