您的位置:首页 > Web前端

Protocol Buffer Basics: Java

2014-05-31 16:56 429 查看
https://developers.google.com/protocol-buffers/docs/javatutorial

Protocol Buffer Basics: Java

This tutorial provides a basic Java programmer's introduction to workingwith protocol buffers. By walking through creating a simple exampleapplication, it shows you how to
这个指南是为java程序员简单介绍一下如何使用protobuf。通过创建一个简单的程序例子,向你展示:

· Define message formats in a .proto file.
· 通过.ptoto文件定义消息格式
· Use the protocol buffer compiler.
· 使用protobuf编译器
· Use the Java protocol buffer API towrite and read messages.
· 使用protobuf JavaAPI读和写消息

This isn't acomprehensive guide to using protocol buffers in Java. For more detailedreference information, see the Protocol
Buffer Language Guide, the Java
API Reference, the Java Generated
Code Guide, and the Encoding Reference.
这不是一个很全面的指南。更详细的内容,请看 Protocol Buffer Language
Guide, Java API Reference,Java
Generated Code Guide,Encoding Reference

Why Use Protocol Buffers?
为什么使用protobuf?

The example we're going to use is a very simple "address book"application that can read and write people's contact details to and from afile. Each person in the address book has a name, an ID, an email address, anda
contact phone number.
我们将使用一个非常简单程序例子“通讯录”,它能从一个文件中,读写人们的联系方式。在通讯录中的每个人有名字、ID、email地址和电话号码。

How do you serialize and retrieve structured data like this? There are afew ways to solve this problem:
怎样序列化和获取数据?解决这个问题有这几种方式:

· Use Java Serialization. This is thedefault approach since it's built into the language, but it has a host ofwell-known problems (see Effective Java, by Josh Bloch pp. 213),
and alsodoesn't work very well if you need to share data with applications written inC++ or Python.
· 使用Java序列化。这是最直接的方式,因为它内建在Java语言中,但是它有许多总所周知的问题(参见EffectiveJava),而且如果你需要和使用其他语言(C++、Python)开发的程序进行通信时,它不能很好的工作。

· You can invent an ad-hoc way toencode the data items into a single string – such as encoding 4 ints as"12:3:-23:67". This is a simple and flexible approach, although itdoes
require writing one-off encoding and parsing code, and the parsing imposesa small run-time cost. This works best for encoding very simple data.
· 你能发明一个专门的方式把一个数据项编码成一个字符串,例如把4个整数编码成“12:3:-23:67”。这是一个简单、灵活的方法,但是编码和解码的代码都是一次性的,并且解析需要消耗一点运行时。这种方式用在编码比较简单的数据。

· Serialize the data to XML. Thisapproach can be very attractive since XML is (sort of) human readable and thereare binding libraries for lots of languages. This can be a
good choice if youwant to share data with other applications/projects. However, XML isnotoriously space intensive, and encoding/decoding it can impose a hugeperformance penalty on applications. Also, navigating an XML DOM tree isconsiderably more complicated
than navigating simple fields in a class normallywould be.
· 把数据序列化为XML。这个方法可能非常诱人,因为XML是人类可读的(某种程度上)并且许多语言都提供了相应的解析库。如果你想和其他应用/项目分享数据,这是一个不错的选择。然后,XML占用空间很大,并且编解码很消耗性能。而且,相比于操作类中的字段,操作XML
DOM树非常的复杂。

Protocolbuffers are the flexible, efficient, automated solution to solve exactly thisproblem. With protocol buffers, you write a .proto description
of the data structure you wish to store. From that, theprotocol buffer compiler creates a class that implements automatic encoding andparsing of the protocol buffer data with an efficient binary format. Thegenerated class provides getters and setters for the
fields that make up aprotocol buffer and takes care of the details of reading and writing theprotocol buffer as a unit. Importantly, the protocol buffer format supports theidea of extending the format over time in such a way that the code can stillread data
encoded with the old format.
Protobuf灵活、高效、自动解决扩展性问题。使用protobuf,将你想存储的数据结构描述在.proto文件中。然后,使用protobuf编译器能生成类,这个生成类,包括get和set字段的方法,能够自动编码和解码protobuf数据,数据格式使用高效的二进制格式。有一点很重要,protobuf格式支持扩展,而且新的代码仍然能够解析使用老格式编码的数据。

Where to Find the Example Code
去哪里寻找示例代码

The examplecode is included in the source code package, under the "examples"directory. Download
ithere.
示例代码包含在“examples”目录下。从这里下载。

Defining Your Protocol Format
定义你的协议格式

To createyour address book application, you'll need to start with a .proto file.
The definitions in a .proto file aresimple: you add a message for
each datastructure you want to serialize, then specify a name and a type for each fieldin the message. Here is the .proto file
thatdefines your messages, addressbook.proto.
创建一个通讯录应用,需要从.proto文件开始。定义.proto文件很简单:将你想序列化的数据结构定义为一个消息,为消息中的每个字段指定名字和类型。这是消息的.proto文件,addressbook.proto。

package tutorial;

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

message AddressBook{
repeated Person person = 1;
}

As you can see, the syntax is similar to C++ or Java. Let's go througheach part of the file and see what it does.
如你所见,语法类似于c++或Java。让我们通过文件中的每个部分,看看它了什么。

The .proto file starts with a package declaration, which helps to prevent
namingconflicts between different projects. In Java, the package name is used as theJava package unless you have explicitly specified a java_package, as
we havehere. Even if you do provide a java_package, you should still define a normal package as
well to avoid name collisions in the Protocol Buffers name space aswell as in non-Java languages.
.proto文件开始于一个package声明,为了防止不同项目之间的名字冲突。在Java中,package被用来作为Java包,除非你明确指定了java_package,像我们做的一样。即使你指定了java_package,你扔需要定义package,以避免非java语言的protobuf名字空间冲突。

After thepackage declaration, you can see two options that are Java-specific: java_package and java_outer_classname. java_package specifies
in what Java package name your generated classes should live. Ifyou don't specify this explicitly, it simply matches the package name given bythe package declaration,but
these names usually aren't appropriate Java package names (since theyusually don't start with a domain name).
声明package后,你能看到两个可选的java属性:java_package和java_outer_classname。java_package定义了生成的java类所在的包。如果没有明确的指定这个属性,将使用package属性简单的匹配java包名,但package属性作为java包名通常是不恰当的,因为它不是一个域名。

The java_outer_classname option defines the class name which should contain
all of the classes inthis file. If you don't give a java_outer_classname explicitly,it will be generated by converting
the file name to camel case. For example,"my_proto.proto" would, by default, use "MyProto" as theouter class name.
Java_outer_classname选项定义类名,这个消息的所有类包含在这个文件中。如果你没有指定这个属性,它将使用proto文件名,以驼峰命名方式生成一个类名。例如,“my_proto.proto”将生成“MyProto”作为类名。

Next, youhave your message definitions. A message is just an aggregate containing a setof typed fields. Many standard simple data types are available as field types,including bool, int32, float, double,
and string. You can also add further structure to your messages by using othermessage types as field types – in the above example the Person message
contains PhoneNumber messages,while the AddressBook messagecontains Person messages.
Youcan even define message types nested inside other messages – as you can see,the PhoneNumber type isdefined inside Person.
You can also define enum types if youwant one of your fields to have one of a predefined list of values – here youwant
to specify that a phone number can be one of MOBILE, HOME,
or WORK.
接下来,定义消息。一个消息是一组有类型的字段的集合。Protobuf提供了许多字段类型:bool,int32,float,double和string。你也能使用消息作为字段类型,来构造复杂的数据结构,在上面的例子中Person消息包含PhoneNumer消息,AddressBook消息包含Person消息。你甚至可以在一个消息里面定义另一个消息,就像PhoneNumber定义在Person里面。你也能定义enum类型,如果你想要的字段是一组预定义的值中的一个,像PhoneType一样。

The " = 1", " = 2" markers on each element identifythe unique "tag" that field uses in the binary encoding. Tag numbers1-15 require one less byte to encode than higher numbers, so as an optimizationyou can decide
to use those tags for the commonly used or repeated elements,leaving tags 16 and higher for less-commonly used optional elements. Eachelement in a repeated field requires re-encoding the tag number, so repeatedfields are particularly good candidates for this
optimization.
“=1”,“=2”使每个字段在二进制编码中有一个唯一的编号。相比于更高的编号,编号1-15需要至少一个字节,所以为了优化,常用的或者数组元素我们可以用这几个编号,高于15的编号用来标记不太常用的可选的元素。数组字段中的每个元素需要重新编码编号,所以数组字段特别适合这种优化。

Each field must be annotated with one of the following modifiers:
每个字段必须使用下面修饰中一种:
· required: a value forthe field must be provided, otherwise the message will be considered"uninitialized". Trying to build an uninitialized
message will throwaRuntimeException. Parsing anuninitialized message will throw an IOException.
Other than this, a required field behavesexactly like an optional field.
· required:这个字段的值必须得有,否则消息将被认为“未初始化”。试图构建一个未初始化的消息将抛出RuntimeException。解析一个未初始化的消息将抛出IOException。除了这点,其余的方面required字段和optional字段表现的一样。
·
· optional: the fieldmay or may not be set. If an optional field value isn't set, a default value isused. For simple types, you can specify
your own default value, as we've donefor the phone number type in theexample. Otherwise, a system default is used: zero
for numeric types, the emptystring for strings, false for bools. For embedded messages, the default valueis always the "default instance" or "prototype" of themessage, which has none of its fields set. Calling the accessor to get thevalue of an optional (or
required) field which has not been explicitly setalways returns that field's default value.
· optional:这个字段可以有值,也可以没有。如果optional字段的值没有设置,将使用默认值。对于简单的类型,你可以设置一个默认值,例子中电话号码的类型就设置了默认值。另外,系统默认值是:数值类型是0,字符串类型是空字符,布尔类型是false。对于嵌入类型,默认值是消息的“默认示例”或“原型”,也就是所有字段的值都没有赋值。调用没有赋值的字段(optional或required)将返回字段的默认值。
·
· repeated: the fieldmay be repeated any number of times (including zero). The order of the repeatedvalues will be preserved in the protocol
buffer. Think of repeated fields asdynamically sized arrays.
repeated:这个字段可以重复任意次(包括0)。Repeated字段数据的顺序将被保存在protobuf中。Repeated字段可以理解为具有动态大小的数组。

Required Is Forever You should be very careful about marking fields as required.
If at somepoint you wish to stop writing or sending a required field, it will beproblematic to change the field to an optional field – old readers willconsider messages without this field to be incomplete and may reject or dropthem unintentionally. You should
consider writing application-specific customvalidation routines for your buffers instead. Some engineers at Google havecome to the conclusion that usingrequired does
more harm than good; they prefer to use only optional and repeated.
However, this view is not universal.
Required Is Forever 指定一个类型为required应该好好考虑一下。如果在某个点你希望停止写或者发送required字段,把这个字段改为optional字段,它将会引起无法预料的问题。因为老程序会认为这个字段没赋值,而无意中拒绝或者抛弃它。在Google的某些工程师认为使用required字段弊大于利;他们更喜欢使用optional和repeated。然而,这个观点不是普遍的。

You'll find acomplete guide to writing .proto files – includingall the possible
field types – in the Protocol Buffer Language Guide.
Don't golooking for facilities similar to class inheritance, though – protocol buffersdon't do that.
在ProtocolBuffer Language Guide中,能找到写.proto文件的完整指南,包括所有可用的字段类型。不用寻找类继承的工具,因为protobuf不能那样做。

Compiling Your Protocol Buffers
编译你的protobuf

Now that youhave a .proto, the next thing you need to do is generate the classes you'll need toread and write AddressBook (and
hence Person and PhoneNumber)
messages. To do this, you need to run theprotocol buffer compiler protoc on your .proto:
现在已经有.proto文件了,接下来我们要生成一个类来读写AddressBook消息。做这些,你需要运行protobuf的编译器protoc。

1. If you haven't installed thecompiler, download
thepackage and followthe instructions in the README.
如果你还没有安装这个编译器,从这里下载并按照README来操作。

2. Now run the compiler, specifying thesource directory (where your application's source code lives – the currentdirectory is used if you don't provide a value), the destination
directory(where you want the generated code to go; often the same as $SRC_DIR), and thepath to your .proto.
In this case, you...:
现在运行编译器,指定源目录、目标目录和.proto文件的路径,在这个例子中,是

protoc -I=$SRC_DIR--java_out=$DST_DIR $SRC_DIR/addressbook.proto

Because you want Java classes, you use the --java_out option – similar options
are provided for other supported languages.
Thisgenerates com/example/tutorial/AddressBookProtos.java in your specified
destination directory.
因为你想要java类,使用—java_out选项,还提供有被支持的其他语言的类似选项。
生成的类com/example/tutorial/AddressBookProtos.java在指定的目标目录中。

The Protocol Buffer API

Let's look atsome of the generated code and see what classes and methods the compiler has createdfor you. If you look in AddressBookProtos.java,
you can see that it defines a classcalled AddressBookProtos, nested within which is a class foreach message you specified in addressbook.proto.
Each class has its own Builder class that you use to create instances of that class. You can find outmore about builders
in the Builders vs. Messages sectionbelow.
让我们看看生成的代码,那些方法和类被编译器生成了。如果你看了AddressBookProtos.java,你能看到定义了一个叫AddressBookProtos的类,addressbook.proto中定义的每个消息都在这个类文件中。每个类有自己的Builder类,用来创建这个类的实例。你能发现更多关于Builder的信息在Builders
vs.Messages部分中。

Both messagesand builders have auto-generated accessor methods for each field of themessage; messages have only getters while builders have both getters andsetters. Here are some of the accessors for the Person class
(implementations omitted for brevity):
Messages和builders都有访问消息每个字段的方法;messages只有get方法,builders
get和set方法都有。这里是Person类的一些方法(为了简洁省去了实现):

// required string name = 1;

public boolean hasName();

public String getName();

// required int32 id = 2;

public boolean hasId();

public int getId();

// optional string email = 3;

public boolean hasEmail();

public String getEmail();

// repeated .tutorial.Person.PhoneNumberphone = 4;

public List<PhoneNumber> getPhoneList();

public int getPhoneCount();

public PhoneNumber getPhone(int index);

Meanwhile, Person.Builder has the same getters plus setters:

// required string name = 1;

public boolean hasName();

public java.lang.String getName();

public Builder setName(String value);

public Builder clearName();

// required int32 id = 2;

public boolean hasId();

public int getId();

public Builder setId(int value);

public Builder clearId();

// optional string email = 3;

public boolean hasEmail();

public String getEmail();

public Builder setEmail(String value);

public Builder clearEmail();

// repeated .tutorial.Person.PhoneNumberphone = 4;

public List<PhoneNumber> getPhoneList();

public int getPhoneCount();

public PhoneNumber getPhone(int index);

public Builder setPhone(int index,PhoneNumber value);

public Builder addPhone(PhoneNumber value);

public Builder addAllPhone(Iterable<PhoneNumber>
value);

public Builder clearPhone();

As you can see,there are simple JavaBeans-style getters and setters for each field. There arealso has getters
foreach singular field which return true if that field has been set. Finally, eachfield has a clear method thatun-sets
the field back to its empty state.
如你所见,简单JavaBean风格的get和set方法,还有has方法,如果这个字段被赋值的话会返回true,clear方法使字段的值返回到未赋值的状态。

Repeatedfields have some extra methods – a Count method (whichis just shorthand
for the list's size), getters and setters which get or set aspecific element of the list by index, an add method which
appends a new element to the list, and an addAll method which adds an entire container full of elements to the list.
Repeated字段有一些额外的方法,count方法,get和set,以及get和set
list中指定下标的元素,add,addAll增加一个或者另一个list的全部元素。

Notice how theseaccessor methods use camel-case naming, even though the .proto file
uses lowercase-with-underscores. This transformation is doneautomatically by the protocol buffer compiler so that the generated classesmatch standard Java style conventions. You should always uselowercase-with-underscores for field names in your.proto files;
thisensures good naming practice in all the generated languages. See the style guide for
more ongood .proto style.
注意这些方法名使用驼峰风格,即使.proto文件中使用小写和下划线的格式。这些转换是protobuf编译器自动完成的,根java风格一致。在.proto文件中字段名应该使用小写字段和下划线;确保所有语言都能用自己的名字风格。从style
guide了解更多关于.proto的风格。

For moreinformation on exactly what members the protocol compiler generates for anyparticular field definition, see the Java
generated code reference.
关于protobuf编译器生成字段的更多信息,请看javagenerated code reference。
Enums and Nested Classes
The generatedcode includes a PhoneType Java 5 enum,nested within Person:

public
static enum
PhoneType {

MOBILE(0,0),

HOME(1,1),

WORK(2,2),

;

...

}

The nestedtype Person.PhoneNumber is generated,as you'd expect, as a nested
class within Person.
Builders vs. Messages
The messageclasses generated by the protocol buffer compiler are all immutable. Once a message object
is constructed, itcannot be modified, just like a Java String. To construct a message, you must first construct a builder, set anyfields you want to set
to your chosen values, then call the builder's build() method.
You may have noticed that each method of the builder which modifies themessage returns another builder. The returned object is actually the samebuilder on which you called the method. It is returned for convenience
so thatyou can string several setters together on a single line of code.
Here's anexample of how you would create an instance of Person:

Person john
=

Person.newBuilder()

.setId(1234)

.setName("John Doe")

.setEmail("jdoe@example.com")

.addPhone(

Person.PhoneNumber.newBuilder()

.setNumber("555-4321")

.setType(Person.PhoneType.HOME))

.build();

Standard Message Methods
Each message and builder class also contains a number of other methods thatlet you check or manipulate the entire message, including:
· isInitialized(): checks ifall the required fields have been set.
· toString(): returns ahuman-readable representation of the message, particularly useful fordebugging.
· mergeFrom(Messageother): (builder only) merges the contents of other into
this message, overwriting singular fields and concatenating repeatedones.
· clear(): (builderonly) clears all the fields back to the empty state.
These methodsimplement the Message and Message.Builder interfaces
shared by all Java messages and builders. For more information,see the complete
API documentation for Message.
Parsing and Serialization
Finally, eachprotocol buffer class has methods for writing and reading messages of yourchosen type using the protocol buffer binary
format. These include:
· byte[] toByteArray();: serializesthe message and returns a byte array containing its raw bytes.
· static PersonparseFrom(byte[] data);: parses a message from the givenbyte array.
· voidwriteTo(OutputStream output);: serializes the message and writesit to an OutputStream.
· static PersonparseFrom(InputStream input);: reads and parses a message from an InputStream.
These arejust a couple of the options provided for parsing and serialization. Again, seethe Message API
reference for a complete list.

Protocol Buffers and O-O Design Protocol buffer classes are basically dumb data holders (like structs inC++); they don't make
good first class citizens in an object model. If you wantto add richer behaviour to a generated class, the best way to do this is towrap the generated protocol buffer class in an application-specific class.Wrapping protocol buffers is also a good idea if you
don't have control over thedesign of the .proto file (if,say, you're reusing one from another project). In that case,
you can use thewrapper class to craft an interface better suited to the unique environment ofyour application: hiding some data and methods, exposing convenience functions,etc. You should never addbehaviour to the
generated classes by inheriting from them
. This willbreak internal mechanisms and is not good object-oriented practice anyway.

Writing A Message

Now let's try using your protocol buffer classes. The first thing you wantyour address book application to be able to do is write personal details toyour address book file. To do this, you need to create and populate
instancesof your protocol buffer classes and then write them to an output stream.
Here is aprogram which reads an AddressBook from a file,adds one new Person to
it basedon user input, and writes the new AddressBook back out tothe file again. The parts which directly call or reference
code generated bythe protocol compiler are highlighted.

import com.example.tutorial.AddressBookProtos.AddressBook;

import com.example.tutorial.AddressBookProtos.Person;

import java.io.BufferedReader;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.InputStreamReader;

import java.io.IOException;

import java.io.PrintStream;

class AddPerson{

// This function fills in a Person message based on user input.

static PersonPromptForAddress(BufferedReader stdin,

PrintStream stdout)throws
IOException{

Person.Builder person=
Person.newBuilder();

stdout.print("Enter person ID: ");

person.setId(Integer.valueOf(stdin.readLine()));

stdout.print("Enter name: ");

person.setName(stdin.readLine());

stdout.print("Enter email address (blank fornone): ");

String email = stdin.readLine();

if (email.length()>
0){

person.setEmail(email);

}

while (true){

stdout.print("Enter a phone number (or leaveblank to finish): ");

String number
= stdin.readLine();

if (number.length()==
0){

break;

}

Person.PhoneNumber.Builder phoneNumber=

Person.PhoneNumber.newBuilder().setNumber(number);

stdout.print("Is this a mobile, home, or workphone? ");

String type
= stdin.readLine();

if (type.equals("mobile")){

phoneNumber.setType(Person.PhoneType.MOBILE);

} elseif
(type.equals("home")){

phoneNumber.setType(Person.PhoneType.HOME);

} elseif
(type.equals("work")){

phoneNumber.setType(Person.PhoneType.WORK);

} else{

stdout.println("Unknown phone type. Usingdefault.");

}

person.addPhone(phoneNumber);

}

return person.build();

}

// Main function: Reads the entire address book from a file,

// adds one person based on user input, then writes it back out tothe same

// file.

public staticvoid main(String[] args)throws
Exception{

if (args.length!=
1){

System.err.println("Usage: AddPerson ADDRESS_BOOK_FILE");

System.exit(-1);

}

AddressBook.Builder addressBook=
AddressBook.newBuilder();

// Read the existing address book.

try {

addressBook.mergeFrom(newFileInputStream(args[0]));

} catch(FileNotFoundException e){

System.out.println(args[0]+
": File not found. Creating anew file.");

}

// Add an address.

addressBook.addPerson(

PromptForAddress(newBufferedReader(newInputStreamReader(System.in)),

System.out));

// Write the new address book back to disk.

FileOutputStream output
= new FileOutputStream(args[0]);

addressBook.build().writeTo(output);

output.close();

}

}

Reading A Message

Of course, an address book wouldn't be much use if you couldn't get anyinformation out of it! This example reads the file created by the above exampleand prints all the information in it.

import com.example.tutorial.AddressBookProtos.AddressBook;

import com.example.tutorial.AddressBookProtos.Person;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.PrintStream;

class ListPeople{

// Iterates though all people in the AddressBook and prints info aboutthem.

static voidPrint(AddressBook addressBook){

for (Person person: addressBook.getPersonList()){

System.out.println("Person ID: "+
person.getId());

System.out.println(" Name: "+
person.getName());

if (person.hasEmail()){

System.out.println(" E-mail address: "+
person.getEmail());

}

for (Person.PhoneNumber phoneNumber: person.getPhoneList()){

switch (phoneNumber.getType()){

case MOBILE:

System.out.print("
Mobile phone #: ");

break;

case HOME:

System.out.print("
Home phone #: ");

break;

case WORK:

System.out.print("
Work phone #: ");

break;

}

System.out.println(phoneNumber.getNumber());

}

}

}

// Main function: Reads the entire address book from a file andprints all

// the information inside.

public staticvoid main(String[] args)throws
Exception{

if (args.length!=
1){

System.err.println("Usage: ListPeople ADDRESS_BOOK_FILE");

System.exit(-1);

}

// Read the existing address book.

AddressBook addressBook
=

AddressBook.parseFrom(newFileInputStream(args[0]));

Print(addressBook);

}

}

Extending a Protocol Buffer

Sooner or later after you release the code that uses your protocol buffer,you will undoubtedly want to "improve" the protocol buffer'sdefinition. If you want your new buffers to be backwards-compatible, and yourold
buffers to be forward-compatible – and you almost certainly do want this –then there are some rules you need to follow. In the new version of theprotocol buffer:
· you must not change the tag numbers of anyexisting fields.
· you must not add or delete any required fields.
· you may delete optional or repeated fields.
· you may add new optional or repeated fieldsbut you must use fresh tag numbers (i.e. tag numbers
that were never used inthis protocol buffer, not even by deleted fields).
(There are some exceptions to
theserules, but they are rarely used.)
If you followthese rules, old code will happily read new messages and simply ignore any newfields. To the old code, optional fields that were deleted will simply havetheir default value, and deleted repeated fields
will be empty. New code willalso transparently read old messages. However, keep in mind that new optionalfields will not be present in old messages, so you will need to either checkexplicitly whether they're set with has_,
or provide a reasonable default value in your .proto file with [default
= value] after the tagnumber. If the default value is not specified for an optional element, atype-specific default value is used instead: for strings, the default value isthe empty string.
For booleans, the default value is false. For numeric types,the default value is zero. Note also that if you added a new repeated field,your new code will not be able to tell whether it was left empty (by new code)or never set at all (by old code) since there
is no has_ flag for it.

Advanced Usage

Protocolbuffers have uses that go beyond simple accessors and serialization. Be sure toexplore the Java
API reference to see whatelse you can do with them.
One keyfeature provided by protocol message classes is reflection. You can iterate over the fields ofa message and manipulate their values
without writing your code against anyspecific message type. One very useful way to use reflection is for convertingprotocol messages to and from other encodings, such as XML or JSON. A moreadvanced use of reflection might be to find differences between two
messages ofthe same type, or to develop a sort of "regular expressions for protocolmessages" in which you can write expressions that match certain messagecontents. If you use your imagination, it's possible to apply Protocol Buffersto a much wider range of
problems than you might initially expect!
Reflection isprovided as part of the Message and Message.Builder interfaces.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: