Google Protocol Buffer is platform neutral, extensible tool for serializing structure data. It is inter-operable and not specific to any language.
In java, we have number of way we can serialized the object, some of the ways are listed below:
1. Java Build-in library : Marker class java.io.Serializable and just implement read,write method in class. But this way, serialized stream can be read/unmarshalled by Java program only.
2. Simple String : Need to implement code to covert to bytes and vice versa.
3. XML : XML DOM parsing can be memory intensive.
Protocol Buffer is flexible,efficient,automated solution to above problem.
In this post, we will be discussing about
1. Creating the .proto file (Structure Data)
2. Generating the automated classes
3. Writing Serialized Data
4. Reading Serialized Data
Prerequisites:
1. Java installed. If not, install.
2. Protocol Buffer installed. If not, install
3. If not maven project download protobuf-java-2.5.0.jar.
If maven project add dependency.
[code language="text"]
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.5.0</version>
</dependency>
[/code]
Note: protoc-java.jar version should be same as protoc --version. Otherwise error will popup java.lang.UnsupportedOperationException: This is supposed to be overridden by subclasses.
Creating the .proto file
Let create a simple structure object PersonAccountsBook embedding the Account object as as shown below:
[code language="text"]
package protobufDemo; //this is protobuf namespace, not java's
option java_package = "com.xxx.protobuf.protobufferData";
option java_outer_classname = "PersonAccountsBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum AccountType{
CHECKING = 0;
SAVING = 1;
VISA = 2;
}
message AccountNumber {
required string number = 1;
optional AccountType type = 2 [default = SAVING];
}
repeated AccountNumber accounts= 4;
}
message PersonAccountsBook {
repeated Person person = 1;
}
[/code]
Now, the Data Type can be any predefined like bool, int32, float, double, and string or user defined as AccountType.The, number specified with fields "=1" or "=2" is unique tags given. Number 1-15 required less code encoding than higher number than 15.
The fields can be
required- If field value required by the structured data like person_id,AccountNumber
optional-If field value has 0 or 1 occurrence
repeated-If field value has 0 to many occurrence.
Generating the automated classes from .proto file
The below code will generate the class PersonAccountsBookProtos in package "com.xxx.protobuf.protobufferData".Note .proto in path project_path/src/java/PersonAccountsBook.proto
[code language="text"]
protoc --java_out=. PersonAccountsBook.proto
[/code]
Writing Serialized Structure Data
In this class we need to provide the person account book file path argument, if file not exist then it will create one. Note: We have Builder class to pass value to the fields as shown below.
[code langugae="text"]
package com.xxx.protobuf;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.PersonAccountsBook;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.Person;
import java.io.*;
public class AddPerson {
// This function fills in a Person message based on user input.
static Person PromptForAddress(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 for none): ");
String email = stdin.readLine();
if (email.length() > 0) {
person.setEmail(email);
}
while (true) {
stdout.print("Enter a Account Number (or leave blank to finish): ");
String number = stdin.readLine();
if (number.length() == 0) {
break;
}
Person.AccountNumber.Builder accountNumber =
Person.AccountNumber.newBuilder().setNumber(number);
stdout.print("Is this a saving,checking,visa account? ");
String type = stdin.readLine();
if (type.equals("saving")) {
accountNumber.setType(Person.AccountType.SAVING);
} else if (type.equals("visa")) {
accountNumber.setType(Person.AccountType.VISA);
} else if (type.equals("checking")) {
accountNumber.setType(Person.AccountType.CHECKING);
} else {
stdout.println("Unknown account type. Using default.");
}
person.addAccounts(accountNumber);
}
return person.build();
}
// Main function: Reads the entire account book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: AddPerson ACCOUNT_BOOK_FILE");
System.exit(-1);
}
PersonAccountsBook.Builder accountBook = PersonAccountsBook.newBuilder();
// Read the existing address book.
try {
accountBook.mergeFrom(new FileInputStream(args[0]));
} catch (FileNotFoundException e) {
System.out.println(args[0] + ": File not found. Creating a new file.");
}
// Add an address.
accountBook.addPerson(
PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
System.out));
// Write the new address book back to disk.
FileOutputStream output = new FileOutputStream(args[0]);
accountBook.build().writeTo(output);
output.close();
}
}
[/code]
Reading Serialized Data
We need to provide person account book file path argument to the java application.
[code langugae="text"]
package com.xxx.protobuf;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.PersonAccountsBook;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.Person;
import java.io.FileInputStream;
public class ListPerson {
// Iterates though all people in the AccountBook and prints info about them.
static void Print(PersonAccountsBook accountBook) {
for (Person person: accountBook.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.AccountNumber accountNumber : person.getAccountsList()) {
switch (accountNumber.getType()) {
case VISA:
System.out.print(" Visa Account #: ");
break;
case SAVING:
System.out.print(" Saving Account #: ");
break;
case CHECKING:
System.out.print(" Checking Account #: ");
break;
}
System.out.println(accountNumber.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: ListPeople Account_BOOK_FILE");
System.exit(-1);
}
// Read the existing address book.
PersonAccountsBook accountBook =
PersonAccountsBook.parseFrom(new FileInputStream(args[0]));
Print(accountBook);
}
}
[/code]
Hope you follow the discussion and it would be useful to you.
References:
Google protocol buffer tutorial
Java Serialization API
In java, we have number of way we can serialized the object, some of the ways are listed below:
1. Java Build-in library : Marker class java.io.Serializable and just implement read,write method in class. But this way, serialized stream can be read/unmarshalled by Java program only.
2. Simple String : Need to implement code to covert to bytes and vice versa.
3. XML : XML DOM parsing can be memory intensive.
Protocol Buffer is flexible,efficient,automated solution to above problem.
In this post, we will be discussing about
1. Creating the .proto file (Structure Data)
2. Generating the automated classes
3. Writing Serialized Data
4. Reading Serialized Data
Prerequisites:
1. Java installed. If not, install.
2. Protocol Buffer installed. If not, install
3. If not maven project download protobuf-java-2.5.0.jar.
If maven project add dependency.
[code language="text"]
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.5.0</version>
</dependency>
[/code]
Note: protoc-java.jar version should be same as protoc --version. Otherwise error will popup java.lang.UnsupportedOperationException: This is supposed to be overridden by subclasses.
Creating the .proto file
Let create a simple structure object PersonAccountsBook embedding the Account object as as shown below:
[code language="text"]
package protobufDemo; //this is protobuf namespace, not java's
option java_package = "com.xxx.protobuf.protobufferData";
option java_outer_classname = "PersonAccountsBookProtos";
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum AccountType{
CHECKING = 0;
SAVING = 1;
VISA = 2;
}
message AccountNumber {
required string number = 1;
optional AccountType type = 2 [default = SAVING];
}
repeated AccountNumber accounts= 4;
}
message PersonAccountsBook {
repeated Person person = 1;
}
[/code]
Now, the Data Type can be any predefined like bool, int32, float, double, and string or user defined as AccountType.The, number specified with fields "=1" or "=2" is unique tags given. Number 1-15 required less code encoding than higher number than 15.
The fields can be
required- If field value required by the structured data like person_id,AccountNumber
optional-If field value has 0 or 1 occurrence
repeated-If field value has 0 to many occurrence.
Generating the automated classes from .proto file
The below code will generate the class PersonAccountsBookProtos in package "com.xxx.protobuf.protobufferData".Note .proto in path project_path/src/java/PersonAccountsBook.proto
[code language="text"]
protoc --java_out=. PersonAccountsBook.proto
[/code]
Writing Serialized Structure Data
In this class we need to provide the person account book file path argument, if file not exist then it will create one. Note: We have Builder class to pass value to the fields as shown below.
[code langugae="text"]
package com.xxx.protobuf;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.PersonAccountsBook;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.Person;
import java.io.*;
public class AddPerson {
// This function fills in a Person message based on user input.
static Person PromptForAddress(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 for none): ");
String email = stdin.readLine();
if (email.length() > 0) {
person.setEmail(email);
}
while (true) {
stdout.print("Enter a Account Number (or leave blank to finish): ");
String number = stdin.readLine();
if (number.length() == 0) {
break;
}
Person.AccountNumber.Builder accountNumber =
Person.AccountNumber.newBuilder().setNumber(number);
stdout.print("Is this a saving,checking,visa account? ");
String type = stdin.readLine();
if (type.equals("saving")) {
accountNumber.setType(Person.AccountType.SAVING);
} else if (type.equals("visa")) {
accountNumber.setType(Person.AccountType.VISA);
} else if (type.equals("checking")) {
accountNumber.setType(Person.AccountType.CHECKING);
} else {
stdout.println("Unknown account type. Using default.");
}
person.addAccounts(accountNumber);
}
return person.build();
}
// Main function: Reads the entire account book from a file,
// adds one person based on user input, then writes it back out to the same
// file.
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage: AddPerson ACCOUNT_BOOK_FILE");
System.exit(-1);
}
PersonAccountsBook.Builder accountBook = PersonAccountsBook.newBuilder();
// Read the existing address book.
try {
accountBook.mergeFrom(new FileInputStream(args[0]));
} catch (FileNotFoundException e) {
System.out.println(args[0] + ": File not found. Creating a new file.");
}
// Add an address.
accountBook.addPerson(
PromptForAddress(new BufferedReader(new InputStreamReader(System.in)),
System.out));
// Write the new address book back to disk.
FileOutputStream output = new FileOutputStream(args[0]);
accountBook.build().writeTo(output);
output.close();
}
}
[/code]
Reading Serialized Data
We need to provide person account book file path argument to the java application.
[code langugae="text"]
package com.xxx.protobuf;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.PersonAccountsBook;
import com.xxx.protobuf.protobufferData.PersonAccountsBookProtos.Person;
import java.io.FileInputStream;
public class ListPerson {
// Iterates though all people in the AccountBook and prints info about them.
static void Print(PersonAccountsBook accountBook) {
for (Person person: accountBook.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.AccountNumber accountNumber : person.getAccountsList()) {
switch (accountNumber.getType()) {
case VISA:
System.out.print(" Visa Account #: ");
break;
case SAVING:
System.out.print(" Saving Account #: ");
break;
case CHECKING:
System.out.print(" Checking Account #: ");
break;
}
System.out.println(accountNumber.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: ListPeople Account_BOOK_FILE");
System.exit(-1);
}
// Read the existing address book.
PersonAccountsBook accountBook =
PersonAccountsBook.parseFrom(new FileInputStream(args[0]));
Print(accountBook);
}
}
[/code]
Hope you follow the discussion and it would be useful to you.
References:
Google protocol buffer tutorial
Java Serialization API
This comment has been removed by a blog administrator.
ReplyDelete