Protobuf for Java

Source: Internet
Author: User
Tags intl

This document provides a basic introduction to Java programmers using protocol buffer, which is described in a simple routine. From this article, you can find the following information:

1. Define an information format in a. proto file.

2. Compile with the PROTOC command to generate Java code.

3. Use the Java protocol Buffer API for read and write operations.

L define Proto file

Take an address book as an example, starting with creating a. proto file, adding a message property to the data interface that needs to be serialized, and specifying a name and type for each field in the message, as follows:

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 for message definitions in C + + and Java is similar, let's look at the meaning of each part:

To avoid naming conflicts, the. proto file begins with a package declaration, and in Java in addition to specifying a Java_package attribute, the package name is typically a Java package. As in the above example, although the Java_package property is provided, you should usually define the package property to avoid naming conflicts in Protocolbuffers. After a package declaration, there are two Java properties: Java_package and Java_outer_classname. Java_package represents the package for the generated Java code, and if not specified, the compiler determines the package name based on the Packages property. The Java_outer_classname property defines the class name of the generated file. If not specified, the conversion is based on the file name, such as: "My_proto.proto" the provincial capital uses Myproto as the external class name.

The next step is to define the message property, a message that contains the aggregation of various types of fields. There are a number of standard variable types that can be used, including: Bool,int32,float,double and String. You can also use a different message as the field type. Just as the person in the example contains the PhoneNumber, and AddressBook contains the persion. You can even define a message inside a message, for example: PhoneNumber is defined in Persion. You can also define an enum type, just like Mobile, HOME, work for the specified phone number type.

where "= 1", "= 2" indicates the identification number of each element, it uses the identity of the domain in the binary encoding. Identification number 1-15 Since the use will be less than those high identification number of one byte, from the perspective of optimization, you can use it on some of the more common or repeated elements, for more than 16 is used on infrequently used or optional elements. For each element of repeated, the identification number needs to be encoded repeatedly, so the repeated domain is optimized to be the most visible.

Each field must provide a modifier:

Ørequired: Indicates that the field must be supplied and cannot be empty. Otherwise, the message is considered uninitialized, and attempting to build an uninitialized message throws runtimeexception. Parsing an uninitialized message throws a IOException. In addition, a required field is exactly the same as the optional field.

Øoptional: Optional field, can be set or not set. If not set, a default value is set. You can specify a default value, just like the Type field of a phone number. Otherwise, the default value of the system is used: the number type defaults to 0, the character type defaults to an empty string, the logical type defaults to False, and for embedded message, the default value is typically an instance or prototype of message.

ørepeated: Fields can be duplicated (including 0) and can be equivalent to dynamic arrays or lists. The order in which the list of values stored is preserved.

Required-modified fields are permanent and must be used with caution when using this modifier. The problem occurs if you later want to modify the required domain to be a optional domain. For users accessing the old interface, the field will be considered illegal and will be rejected or discarded. Some of Google's engineers suggested that if not required, try to use less required modifiers.

L Compile Protocol buffers file

Now that you have the. proto file, you will need to compile the. proto file with the compiler PROTOC to generate the specific Java class. You can read and write addressbook, person, and personnumber messages.

protoc-i= $SRC _dir--java_out= $DST _dir $SRC _dir/addressbook.proto

$SRC _dir: Represents the directory where the. proto file is located; $DST _dir: The folder that generated the Java code.

After the compilation succeeds, the Java code file is generated in the specified directory, including the operation of the property, and the next step is to read and write the data through the API.

L Protocol Buffer API uses

Next, take a look at the generated Java code and the methods in it. As you can see in Addressbookprotos.java, the inner class corresponds to the format defined in Addressbook.proto. Each class has its own builder class, through which it can create an instance of the class. You can find more information about builder in the http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/javatutorial.html#builders.

Both messages and builders create automatic access methods for each domain, where messages is getters only, and builders has getters and setters. The following is the access method for the person class message:

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.phonenumber phone = 4; Public list<phonenumber> getphonelist (); public int getphonecount (); Public phonenumber getphone (int index);

Access method for Person class Builder (Person.builder):

//Required String name = 1; pub Lic 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 valu e); Public Builder clearemail ();
//repeated. Tutorial. Person.phonenumber phone = 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 javabean-style getters and setters for each domain. For types with a single value, there is a has method used to indicate whether the value has a setting. It is also possible to clear the value of the field by using the clear method.

Repeating fields also have additional methods, such as the Count method used to count the size of the current repeating field, and getters and setters are used to get or set the value based on the index. The Add method is used to add a new element to the repeating field, and the AddAll method adds a set of elements to the repeating field.

The name of the access method in the example above is camel-named and corresponds to a lowercase + underscore named in the. proto file. This conversion is done automatically by the Protoc compiler, and we only need to define the. proto file according to this specification.

L Enumerations and inner classes

The generated code contains an enumeration type Phonetype, which belongs to the inner class of person:

public static enum Phonetype {MOBILE (0, 0), HOME (1, 1), Work (2, 2),; ... }

PhoneNumber is also produced as an inner class of person.

L Builders to messages

The message class generated automatically by the compiler is immutable, and once a message object is built, it is as immutable as the string class in Java. When you create a message, you must first create a builder, set some of the necessary values, and then call the builder's build () method.

You may have noticed that each of the builder's methods returns to builder after the message has been modified, and the return object can call other methods. This approach provides a convenient way to operate differently on the same line. As the following code example, create a person instance.

Person John = Person.newbuilder (). SetId (1234). SetName ("John Doe"). Setemail ("[email protected]"). ADDP Hone (Person.PhoneNumber.newBuilder (). Setnumber ("555-4321"). SetType (Person.PhoneType.HOME)). b Uild ();

L Standard Message method

For each message or builder class, it also contains methods for checking or manipulating the entire messages, such as:

· isInitialized(): Check whether all the required fields have been set to a value;

· toString(): Returns an easy-to-read message result, which is useful for debugging purposes;

· mergeFrom(Message other): Add other internal merger to the current message, rewrite a single domain or add a repeated field, for builder only.

· clear(): Clears all domain settings for builder only.

L parsing and serialization

Finally, the protocol buffer class can be used to read and write messages in a number of ways. Such as:

· The byte[] toByteArray() message is serialized and returns an array of bytes;

· static Person parseFrom(byte[] data) parse from a specific byte array into a message;

· void writeTo(OutputStream output) serializes the message and writes it to the OutputStream;

· static Person parseFrom(InputStreaminput) reads and parses a message from the InputStream stream.

The above provides only a set of interfaces for parsing and serialization, which can be used in http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/reference/java/com/google/ A more comprehensive interface is available in the protobuf/message.html.

L Write Messages

Next look at how to use the protocol buffer class, for the Address Book application first need to write personal data into the Address book. In order to do this, you need to create a protocol buffer class and write the information. Program design as follows, will be read from a file addressbook information, through the user manually input a person's information, hand it back to write to the AddressBook file. The code example below, where the highlighted part is the code that PROTOBUF automatically generates.

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-a person message based on user input. Static person promptforaddress (BufferedReader stdin, PrintStream stdout) throws Ioexcepti on {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 for none):");     String email = stdin.readline ();     if (email.length () > 0) {person.setemail (email); }
while (true) {Stdout.print ("Enter a phone number (or leave blank 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 work phone?");       String type = Stdin.readline ();       if (Type.equals ("mobile")) {Phonenumber.settype (Person.PhoneType.MOBILE);       } else if (Type.equals ("Home")) {Phonenumber.settype (Person.PhoneType.HOME);       } else if (Type.equals ("work")) {Phonenumber.settype (Person.PhoneType.WORK);  } else {stdout.println ("Unknown phone type. Using default. ");}
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 b   ACK out to the same//file. public static void Main (string[] args) throws Exception {if (args.length! = 1) {System.err.println ("Usage:ad       Dperson address_book_file ");     System.exit (-1); }
Addressbook.builder addressbook = Addressbook.newbuilder ();
Read the existing address book.     try {addressbook.mergefrom (new FileInputStream (Args[0]));  } catch (FileNotFoundException e) {System.out.println (Args[0] + ": File not found. Creating a new file. ");
Add an address.                        Addressbook.addperson (Promptforaddress (New BufferedReader (system.in)), System.out));
Write The new Address book back to disk.     FileOutputStream output = new FileOutputStream (args[0]);     Addressbook.build (). WriteTo (output);   Output.close (); } }

L Read Messages

Of course, if only the address book can not read is a tragic thing, the following code example is to read from the file address in the personal details of the address book.

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 about them. static void Print (AddressBook addressbook) {for (Person person:addressBook.getPersonList ()) {System.out.print       ln ("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 MOB             ILE: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 and prints all//the information inside. public static void Main (string[] args) throws Exception {if (args.length! = 1) {System.err.println ("Usage:li       Stpeople address_book_file ");     System.exit (-1); }
Read the existing address book. AddressBook addressbook = Addressbook.parsefrom (new FileInputStream (Args[0]));
Print (AddressBook); } }

L extend the protocol buffer

It is sometimes found that you need to extend the upgrade after you publish the Protocolbuffer code. If you want to make the new code backwards compatible, and the old code is forward compatible, you need to follow the rules below.

· The identification number of the existing domain cannot be changed;

· Do not arbitrarily add or remove required decorated fields;

· You can delete optional or repeated-modified fields;

· You can add a optional or repeated decorated domain, but you must use the new identification number.

If the above protocol is upgraded, the old code will be able to read the new message and omit some new fields. For the old code, the deleted optional domain will use its default value, and the deleted repeated domain will be empty. The new code will also be able to read the old message transparently, but one thing to be clear is that the new optional domain cannot appear in the old message, can be explicitly checked by the has method, or provide a default value for the field in the. proto file. If a optional element does not explicitly declare the default value, it will take the default value according to its type, such as: String type, empty string is the default value, Boolean type takes false to its default value, numeric type takes 0 as its default value. If you add a repeated field, the new code will not be able to tell if it is empty, the old code does not set its value, and it does not have the has method.

L Advanced Usage

Protocol buffers has now been able to provide far more functionality than the simple access and serialization described above, and can be used in http://code.google.com/intl/zh-CN/apis/protocolbuffers/docs/ Discover more advanced features in the reference/java/index.html.

One of the main features provided by the Protocol message class is reflection, which allows you to iterate over the fields and manipulate the values in any specific message type without writing code. Its effective application scenarios can transform other encoded (XML, JSON) messages into protocol messages. A more advanced reflection application can discover the difference between messages of the same type, or use a series of regular expressions to match certain message content. With full imagination, protocol buffer will be able to solve a wider range of problems. Where reflection is provided as part of the interface of message and Message.builder.

Protobuf for Java

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.