中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

基于Protobuf動態解析在Java中的應用 包含例子程序

發布時間:2020-10-21 11:19:29 來源:腳本之家 閱讀:238 作者:jingxian 欄目:編程語言

最近在做ProtoBuf相關的項目,其中用到了動態解析,網上看了下相關資料和博文都比較少,自己來寫一個記錄一下學習過程。

Protocol Buffers是結構化數據格式標準,提供序列化和反序列方法,用于存儲和交換。語言中立,平臺無關、可擴展。目前官方提供了C++、Java、Python API,也有其他語言的開源api(比如php)。可通過 .proto文件生成對應語言的類代碼
如果已知protobuf內容對應的是哪個類對象,則可以直接使用反序列化方法搞定(Xxx.parseFrom(inputStream)由二進制轉換,TextFormat.merge(string, xxxBuilder)由文本轉換)

而我們經常遇到的情況是,拿到一個被protobuf序列化的二進制內容,但不知道它的類型,無法獲得對應的類對象。這種多見于需要處理各種各樣未知的ProtoBuf對象的系統。ProtoBuf提供了動態解析機制來解決這個問題,它要求提供二進制內容的基礎上,再提供對應類的Descriptor對象,在解析時通過DynamicMessage類的成員方法來獲得對象結果。
最后問題就是Descriptor對象從哪里來?這是通過protoc --descriptor_set_out=$outputpath 命令生成descriptor文件,進而得到的。

代碼如下:

 cinema.proto

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;
}

Main.java

public static void main( String[] args ) {

  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();
   }
   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();
  }
 }

執行結果:

Dynamic Message Parse From byte array
[B@597ccf6e
Movie descriptor found
name: "The Shining"
type: ADULT
releaseTimeStamp: 327859200

 解釋具體過程:

0.首先對.proto文件使用protoc命令,生成的descriptor文件中包含多個類對應的descriptor類信息(序列化的DescriptorSet內容)

1.首先取出序列化的DescriptorSet內容,FileDescriptorSet.parseFrom方法反序列化得到FileDescriptorSet對象

2.取出對應message類型的Descriptor。

 DescriptorSet成員方法getFileList(),拿到多個FileDescriptorProto對象,再構建對應FileDescriptor。
 FileDescriptor的成員方法getMessageTypes()得到所有Message的Descriptor對象,找到對應名字的Descriptor

3.用Descriptor對象反序列化對象

構建DynamicMessage.Builder對象builder,再調用builder的mergeFrom/merge方法得到Message對象

其中Descriptor相關類:

DescriptorProtos.DescriptorSet:protoc編譯出來類文件中包含這個類,描述多個.proto文件中的類

DescriptorProtos.FileDescriptorProto:描述一個完整的.proto文件中的類

DescriptorProtos.FileDescriptor:由DescriptorProtos.FileDescriptorProto構建而來(buildFrom),描述1個完整.proto文件中的所有內容,包括message類型的Descriptor和其他被導入文件的Descriptor。

getMessageTypes()方法:返回List<Descriptors.Descriptor>。得到FileDescriptor內,所有message類型直接兒子的Descriptor列表   

DescriptorProtos.Descriptor:描述一個message類型,通過getName()得到message的類名

以上這篇基于Protobuf動態解析在Java中的應用 包含例子程序就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

晋中市| 岢岚县| 雅江县| 濮阳县| 阜阳市| 响水县| 囊谦县| 泰安市| 比如县| 砀山县| 鲁甸县| 昌江| 义乌市| 稻城县| 河北区| 望江县| 工布江达县| 阿鲁科尔沁旗| 吐鲁番市| 铅山县| 乐至县| 斗六市| 图木舒克市| 喀喇沁旗| 大洼县| 保定市| 景泰县| 昌都县| 北海市| 扬中市| 红河县| 南昌县| 敦煌市| 册亨县| 侯马市| 黄龙县| 桐庐县| 宜宾市| 通化县| 夏邑县| 昭通市|