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."""