`

Protocol Buffers - Google's data interchange format

 
阅读更多

http://code.google.com/p/protobuf/

Protocol Buffers are a way of encoding structured data in an efficient yet extensible format. Google uses Protocol Buffers for almost all of its internal RPC protocols and file formats.

 

  • Options

http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/proto.html#options

 

1. java_package (file option): The package you want to use for your generated Java classes.

option java_package = "com.example.foo";

2. java_outer_classname (file option): The class name for the outermost Java class (and hence the file name) you want to generate.

option java_outer_classname = "Ponycopter";

3. optimize_for (file option): Can be set to SPEED , CODE_SIZE , or LITE_RUNTIME .

option optimize_for = CODE_SIZE;

 

http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/reference/java-generated.html

 

  • 根据反编译后的Java文件推导出proto文件

首先看看下面的proto文件生成的Java文件是什么样子的:

package tutorial;

option optimize_for = LITE_RUNTIME;
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";

message Person {
  required string name = 1;
  required int32 id = 2;
  optional string email = 3;
  

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
  optional bytes addressBytes = 6;
}

message AddressBook {
  repeated Person person = 1;
}
 

 

枚举类型会生成Java中的枚举:

public enum PhoneType
        implements com.google.protobuf.Internal.EnumLite {
      MOBILE(0, 0),
      HOME(1, 1),
      WORK(2, 2),
      ;
      
      public static final int MOBILE_VALUE = 0;
      public static final int HOME_VALUE = 1;
      public static final int WORK_VALUE = 2;
      ...
}

 注意同时会生成一个以_VALUE作为后缀的常量。

 

下面的三个域生成的Java代码是什么样子呢?

required string name = 1;
required int32 id = 2;
optional string email = 3;

 

首先生成一个接口PersonOrBuilder,有下面的方法:

    boolean hasName();
    String getName();

    boolean hasId();
    int getId();
    
    boolean hasEmail();
    String getEmail();

然后生成Person类,实现接口PersonOrBuilder,同时,定义了下面的常量:

public static final int NAME_FIELD_NUMBER = 1;
public static final int ID_FIELD_NUMBER = 2;
public static final int EMAIL_FIELD_NUMBER = 3;

 可以看出,都有_FIELD_NUMBER后缀。

 

可以从isInitialized()函数中看判断某个域是optional还是required。optional的域不会在isInitialized()中进行检查。

public final boolean isInitialized() {
        if (!hasName()) {
          
          return false;
        }
        if (!hasId()) {
          
          return false;
        }
        ...
}

 

对于域是一个message而不是原始类型的情况,判断是optional还是required有些区别:

比如,对于如下的proto:

optional PhoneNumber mobile = 7;
required PhoneNumber cell = 8;

 对于的Java代码为:

      if (!hasCell()) {
        memoizedIsInitialized = 0;
        return false;
      }
      if (hasMobile()) {
        if (!getMobile().isInitialized()) {
          memoizedIsInitialized = 0;
          return false;
        }
      }
      if (!getCell().isInitialized()) {
        memoizedIsInitialized = 0;
        return false;
      }

 对于required message field, Java代码中会首先用一个if语句块hasXxx()判断,然后再用一个if语句块getXxx().isInitialized()进行判断,而对于optional message field,两个if语句块会嵌套一起。

 

在initFields()函数中查看具体有哪些fields,再结合XXX_FIELD_NUMBER一起分析。

 

判断extensions:

查看registerAllExtensions()函数。

通常是使用nested extensions,需要好好理解,其实很简单,只是写法有点绕:

http://code.google.com/apis/protocolbuffers/docs/proto.html#extensions
http://code.google.com/apis/protocolbuffers/docs/reference/java-generated.html#extension

 

下面的例子:

public static final int MAN_FIELD_NUMBER = 123;
    public static final
      com.google.protobuf.GeneratedMessageLite.GeneratedExtension<
        com.example.tutorial.AddressBookProtos.Person,
        com.example.tutorial.AddressBookProtos.Man> man = com.google.protobuf.GeneratedMessageLite
            .newSingularGeneratedExtension(
          com.example.tutorial.AddressBookProtos.Person.getDefaultInstance(),
          com.example.tutorial.AddressBookProtos.Man.getDefaultInstance(),
          com.example.tutorial.AddressBookProtos.Man.getDefaultInstance(),
          null,
          123,
          com.google.protobuf.WireFormat.FieldType.MESSAGE);
  }

 可以得知Man是Person的extension,并且field number是123.

 

LazyStringList对应 repeat string xxx = 1;

this change coming up in 2.4.0:
"""Added lazy conversion of UTF-8 encoded strings to String objects to improve
performance."""

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics