Serialization and Deserialization using Protocol Buffers
What are Protocol Buffers?
Protocol buffers (also referred to as Protobuf) are Google's language-neutral, platform-neutral, extensible mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages.
What is Protocol Buffers used for?
Protocol buffers provide a language-neutral, platform-neutral, extensible mechanism for serializing structured data in a forward-compatible and backward-compatible way. It's like JSON, except it's smaller and faster, and it generates native language bindings.
What makes Protocol Buffers faster than JSON or XML ?
Protobuf has a defined format. It has data-types and other required keywords which are not needed to be encoded/decoded during the serialization/deserialization. So there is faster serialization and deserialization and even lesser content generated for protobuf. JSON provides only curly brackets and colons as inbuilt characters and same applies to XML too. Rest all needs to be encoded.
For this article, we will use Java to serialize and deserialize objects using Protobuf.
Project Setup
Create a maven project and open it in any IDE of your preference (Intellij , Eclipse, VSCode, etc.)
In the pom.xml , add the following dependencies and maven plugins.
pom.xml
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.47.0</version>
</dependency>
<dependency> <!-- necessary for Java 9+ -->
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.1</version>
<configuration>
<protocArtifact>
com.google.protobuf:protoc:3.19.2:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>
io.grpc:protoc-gen-grpc-java:1.47.0:exe:${os.detected.classifier}
</pluginArtifact>
<protoSourceRoot>
${basedir}/src/main/proto/
</protoSourceRoot>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.os72</groupId>
<artifactId>protoc-jar-maven-plugin</artifactId>
<version>3.11.4</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<protocVersion>3.0.0</protocVersion> <!-- 2.4.1, 2.5.0, 2.6.1, 3.0.0 -->
<includeDirectories>
<include>src/main/resources/protobuf</include>
</includeDirectories>
<inputDirectories>
<include>src/main/resources/protobuf/</include>
</inputDirectories>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
${basedir}/src/main/proto/
is used to specify that all the proto files should be placed in this directory. You can change it to whichever location you wish, but this is a standard practice by the community.
Create a proto file.
Lets create out first simple proto file srudent.proto
containing 2 fields - name and age. Make sure to place it under /src/main/proto/
directory.
student.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.protobufdemo.models";
message Student {
string name = 1;
int32 age = 2;
}
Here, syntax = "proto3";
specifies the syntax whether we are using proto2 or proto3. By specifying option java_multiple_files = true;
, instead of creating one single file with all aggregated functionality, multiple classed will be generated for our ease of use. option java_package = "com.protobufdemo.models";
specifes the package which will contain our generated classes to keep them organized and if we need to create jar files for running or deploying purposes.
Here is a list of Proto types corresponding to their java types.
Java Type | Proto Type |
---|---|
int | int32 |
long | int64 |
float | float |
double | double |
boolean | bool |
String | string |
byte[] | bytes |
Collection / List | repeated |
Map | map |
Now with this in place, run the command
mvn compile
You will see in the target/generated-sources/protobuf/java
, our classes get created.
The generated Student class will look like this
Student.java (generated)
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: student.proto
package com.protobufdemo.models;
/**
* Protobuf type {@code Student}
*/
public final class Student extends
com.google.protobuf.GeneratedMessageV3 implements
// @@protoc_insertion_point(message_implements:Student)
StudentOrBuilder {
private static final long serialVersionUID = 0L;
// Use Student.newBuilder() to construct.
private Student(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
super(builder);
}
private Student() {
name_ = "";
}
@java.lang.Override
@SuppressWarnings({"unused"})
protected java.lang.Object newInstance(
UnusedPrivateParameter unused) {
return new Student();
}
@java.lang.Override
public final com.google.protobuf.UnknownFieldSet
getUnknownFields() {
return this.unknownFields;
}
private Student(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
this();
if (extensionRegistry == null) {
throw new java.lang.NullPointerException();
}
com.google.protobuf.UnknownFieldSet.Builder unknownFields =
com.google.protobuf.UnknownFieldSet.newBuilder();
try {
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
case 0:
done = true;
break;
case 10: {
java.lang.String s = input.readStringRequireUtf8();
name_ = s;
break;
}
case 16: {
age_ = input.readInt32();
break;
}
default: {
if (!parseUnknownField(
input, unknownFields, extensionRegistry, tag)) {
done = true;
}
break;
}
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
throw e.setUnfinishedMessage(this);
} catch (java.io.IOException e) {
throw new com.google.protobuf.InvalidProtocolBufferException(
e).setUnfinishedMessage(this);
} finally {
this.unknownFields = unknownFields.build();
makeExtensionsImmutable();
}
}
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return com.protobufdemo.models.StudentOuterClass.internal_static_Student_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return com.protobufdemo.models.StudentOuterClass.internal_static_Student_fieldAccessorTable
.ensureFieldAccessorsInitialized(
com.protobufdemo.models.Student.class, com.protobufdemo.models.Student.Builder.class);
}
public static final int NAME_FIELD_NUMBER = 1;
private volatile java.lang.Object name_;
/**
* <code>string name = 1;</code>
* @return The name.
*/
@java.lang.Override
public java.lang.String getName() {
java.lang.Object ref = name_;
if (ref instanceof java.lang.String) {
return (java.lang.String) ref;
} else {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
name_ = s;
return s;
}
}
/**
* <code>string name = 1;</code>
* @return The bytes for name.
*/
@java.lang.Override
public com.google.protobuf.ByteString
getNameBytes() {
java.lang.Object ref = name_;
if (ref instanceof java.lang.String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
name_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
public static final int AGE_FIELD_NUMBER = 2;
private int age_;
/**
* <code>int32 age = 2;</code>
* @return The age.
*/
@java.lang.Override
public int getAge() {
return age_;
}
private byte memoizedIsInitialized = -1;
@java.lang.Override
public final boolean isInitialized() {
byte isInitialized = memoizedIsInitialized;
if (isInitialized == 1) return true;
if (isInitialized == 0) return false;
memoizedIsInitialized = 1;
return true;
}
@java.lang.Override
public void writeTo(com.google.protobuf.CodedOutputStream output)
throws java.io.IOException {
if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) {
com.google.protobuf.GeneratedMessageV3.writeString(output, 1, name_);
}
if (age_ != 0) {
output.writeInt32(2, age_);
}
unknownFields.writeTo(output);
}
@java.lang.Override
public int getSerializedSize() {
int size = memoizedSize;
if (size != -1) return size;
size = 0;
if (!com.google.protobuf.GeneratedMessageV3.isStringEmpty(name_)) {
size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, name_);
}
if (age_ != 0) {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(2, age_);
}
size += unknownFields.getSerializedSize();
memoizedSize = size;
return size;
}
@java.lang.Override
public boolean equals(final java.lang.Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof com.protobufdemo.models.Student)) {
return super.equals(obj);
}
com.protobufdemo.models.Student other = (com.protobufdemo.models.Student) obj;
if (!getName()
.equals(other.getName())) return false;
if (getAge()
!= other.getAge()) return false;
if (!unknownFields.equals(other.unknownFields)) return false;
return true;
}
@java.lang.Override
public int hashCode() {
if (memoizedHashCode != 0) {
return memoizedHashCode;
}
int hash = 41;
hash = (19 * hash) + getDescriptor().hashCode();
hash = (37 * hash) + NAME_FIELD_NUMBER;
hash = (53 * hash) + getName().hashCode();
hash = (37 * hash) + AGE_FIELD_NUMBER;
hash = (53 * hash) + getAge();
hash = (29 * hash) + unknownFields.hashCode();
memoizedHashCode = hash;
return hash;
}
public static com.protobufdemo.models.Student parseFrom(
java.nio.ByteBuffer data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.protobufdemo.models.Student parseFrom(
java.nio.ByteBuffer data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.protobufdemo.models.Student parseFrom(
com.google.protobuf.ByteString data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.protobufdemo.models.Student parseFrom(
com.google.protobuf.ByteString data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.protobufdemo.models.Student parseFrom(byte[] data)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data);
}
public static com.protobufdemo.models.Student parseFrom(
byte[] data,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return PARSER.parseFrom(data, extensionRegistry);
}
public static com.protobufdemo.models.Student parseFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static com.protobufdemo.models.Student parseFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
public static com.protobufdemo.models.Student parseDelimitedFrom(java.io.InputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input);
}
public static com.protobufdemo.models.Student parseDelimitedFrom(
java.io.InputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseDelimitedWithIOException(PARSER, input, extensionRegistry);
}
public static com.protobufdemo.models.Student parseFrom(
com.google.protobuf.CodedInputStream input)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input);
}
public static com.protobufdemo.models.Student parseFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
return com.google.protobuf.GeneratedMessageV3
.parseWithIOException(PARSER, input, extensionRegistry);
}
@java.lang.Override
public Builder newBuilderForType() { return newBuilder(); }
public static Builder newBuilder() {
return DEFAULT_INSTANCE.toBuilder();
}
public static Builder newBuilder(com.protobufdemo.models.Student prototype) {
return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
}
@java.lang.Override
public Builder toBuilder() {
return this == DEFAULT_INSTANCE
? new Builder() : new Builder().mergeFrom(this);
}
@java.lang.Override
protected Builder newBuilderForType(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
Builder builder = new Builder(parent);
return builder;
}
/**
* Protobuf type {@code Student}
*/
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
// @@protoc_insertion_point(builder_implements:Student)
com.protobufdemo.models.StudentOrBuilder {
public static final com.google.protobuf.Descriptors.Descriptor
getDescriptor() {
return com.protobufdemo.models.StudentOuterClass.internal_static_Student_descriptor;
}
@java.lang.Override
protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
internalGetFieldAccessorTable() {
return com.protobufdemo.models.StudentOuterClass.internal_static_Student_fieldAccessorTable
.ensureFieldAccessorsInitialized(
com.protobufdemo.models.Student.class, com.protobufdemo.models.Student.Builder.class);
}
// Construct using com.protobufdemo.models.Student.newBuilder()
private Builder() {
maybeForceBuilderInitialization();
}
private Builder(
com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
super(parent);
maybeForceBuilderInitialization();
}
private void maybeForceBuilderInitialization() {
if (com.google.protobuf.GeneratedMessageV3
.alwaysUseFieldBuilders) {
}
}
@java.lang.Override
public Builder clear() {
super.clear();
name_ = "";
age_ = 0;
return this;
}
@java.lang.Override
public com.google.protobuf.Descriptors.Descriptor
getDescriptorForType() {
return com.protobufdemo.models.StudentOuterClass.internal_static_Student_descriptor;
}
@java.lang.Override
public com.protobufdemo.models.Student getDefaultInstanceForType() {
return com.protobufdemo.models.Student.getDefaultInstance();
}
@java.lang.Override
public com.protobufdemo.models.Student build() {
com.protobufdemo.models.Student result = buildPartial();
if (!result.isInitialized()) {
throw newUninitializedMessageException(result);
}
return result;
}
@java.lang.Override
public com.protobufdemo.models.Student buildPartial() {
com.protobufdemo.models.Student result = new com.protobufdemo.models.Student(this);
result.name_ = name_;
result.age_ = age_;
onBuilt();
return result;
}
@java.lang.Override
public Builder clone() {
return super.clone();
}
@java.lang.Override
public Builder setField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.setField(field, value);
}
@java.lang.Override
public Builder clearField(
com.google.protobuf.Descriptors.FieldDescriptor field) {
return super.clearField(field);
}
@java.lang.Override
public Builder clearOneof(
com.google.protobuf.Descriptors.OneofDescriptor oneof) {
return super.clearOneof(oneof);
}
@java.lang.Override
public Builder setRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
int index, java.lang.Object value) {
return super.setRepeatedField(field, index, value);
}
@java.lang.Override
public Builder addRepeatedField(
com.google.protobuf.Descriptors.FieldDescriptor field,
java.lang.Object value) {
return super.addRepeatedField(field, value);
}
@java.lang.Override
public Builder mergeFrom(com.google.protobuf.Message other) {
if (other instanceof com.protobufdemo.models.Student) {
return mergeFrom((com.protobufdemo.models.Student)other);
} else {
super.mergeFrom(other);
return this;
}
}
public Builder mergeFrom(com.protobufdemo.models.Student other) {
if (other == com.protobufdemo.models.Student.getDefaultInstance()) return this;
if (!other.getName().isEmpty()) {
name_ = other.name_;
onChanged();
}
if (other.getAge() != 0) {
setAge(other.getAge());
}
this.mergeUnknownFields(other.unknownFields);
onChanged();
return this;
}
@java.lang.Override
public final boolean isInitialized() {
return true;
}
@java.lang.Override
public Builder mergeFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws java.io.IOException {
com.protobufdemo.models.Student parsedMessage = null;
try {
parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
parsedMessage = (com.protobufdemo.models.Student) e.getUnfinishedMessage();
throw e.unwrapIOException();
} finally {
if (parsedMessage != null) {
mergeFrom(parsedMessage);
}
}
return this;
}
private java.lang.Object name_ = "";
/**
* <code>string name = 1;</code>
* @return The name.
*/
public java.lang.String getName() {
java.lang.Object ref = name_;
if (!(ref instanceof java.lang.String)) {
com.google.protobuf.ByteString bs =
(com.google.protobuf.ByteString) ref;
java.lang.String s = bs.toStringUtf8();
name_ = s;
return s;
} else {
return (java.lang.String) ref;
}
}
/**
* <code>string name = 1;</code>
* @return The bytes for name.
*/
public com.google.protobuf.ByteString
getNameBytes() {
java.lang.Object ref = name_;
if (ref instanceof String) {
com.google.protobuf.ByteString b =
com.google.protobuf.ByteString.copyFromUtf8(
(java.lang.String) ref);
name_ = b;
return b;
} else {
return (com.google.protobuf.ByteString) ref;
}
}
/**
* <code>string name = 1;</code>
* @param value The name to set.
* @return This builder for chaining.
*/
public Builder setName(
java.lang.String value) {
if (value == null) {
throw new NullPointerException();
}
name_ = value;
onChanged();
return this;
}
/**
* <code>string name = 1;</code>
* @return This builder for chaining.
*/
public Builder clearName() {
name_ = getDefaultInstance().getName();
onChanged();
return this;
}
/**
* <code>string name = 1;</code>
* @param value The bytes for name to set.
* @return This builder for chaining.
*/
public Builder setNameBytes(
com.google.protobuf.ByteString value) {
if (value == null) {
throw new NullPointerException();
}
checkByteStringIsUtf8(value);
name_ = value;
onChanged();
return this;
}
private int age_ ;
/**
* <code>int32 age = 2;</code>
* @return The age.
*/
@java.lang.Override
public int getAge() {
return age_;
}
/**
* <code>int32 age = 2;</code>
* @param value The age to set.
* @return This builder for chaining.
*/
public Builder setAge(int value) {
age_ = value;
onChanged();
return this;
}
/**
* <code>int32 age = 2;</code>
* @return This builder for chaining.
*/
public Builder clearAge() {
age_ = 0;
onChanged();
return this;
}
@java.lang.Override
public final Builder setUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.setUnknownFields(unknownFields);
}
@java.lang.Override
public final Builder mergeUnknownFields(
final com.google.protobuf.UnknownFieldSet unknownFields) {
return super.mergeUnknownFields(unknownFields);
}
// @@protoc_insertion_point(builder_scope:Student)
}
// @@protoc_insertion_point(class_scope:Student)
private static final com.protobufdemo.models.Student DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new com.protobufdemo.models.Student();
}
public static com.protobufdemo.models.Student getDefaultInstance() {
return DEFAULT_INSTANCE;
}
private static final com.google.protobuf.Parser<Student>
PARSER = new com.google.protobuf.AbstractParser<Student>() {
@java.lang.Override
public Student parsePartialFrom(
com.google.protobuf.CodedInputStream input,
com.google.protobuf.ExtensionRegistryLite extensionRegistry)
throws com.google.protobuf.InvalidProtocolBufferException {
return new Student(input, extensionRegistry);
}
};
public static com.google.protobuf.Parser<Student> parser() {
return PARSER;
}
@java.lang.Override
public com.google.protobuf.Parser<Student> getParserForType() {
return PARSER;
}
@java.lang.Override
public com.protobufdemo.models.Student getDefaultInstanceForType() {
return DEFAULT_INSTANCE;
}
}
Notice that the Person class is final , hence it cannot be extended and also the constructor is private , so we cannot create objects using new
keyword. Protobuf uses builder pattern
to create objects.
Now lets create our first object using our generated Student.java class. Create a class StudentDemo.java
.
StudentDemo.java;
import com.protobufdemo.models.Student;
public class StudentDemo
{
public static void main(String[] args)
{
Student Alex = Student
.newBuilder()
.setName("Alex")
.setAge(20)
.build();
System.out.println(Alex);
}
}
Console Output
name: "Alex"
age: 20
Serializing the object
Lets Serialize our student class object and save it to a local file. We'll create a seperate class StudentSerialize.java
StudentSerialize.java
import com.protobufdemo.models.Student;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class StudentSerialize
{
public static void main(String[] args) throws IOException {
// Create the student object
Student Alex = Student
.newBuilder()
.setName("Alex")
.setAge(20)
.build();
// Get the file path
Path path = Paths.get("Alex.ser");
// Convert the object to bytes and store it in the file.
Files.write(path, Alex.toByteArray());
}
}
Run the main()
method of the StudentSerialize class and you will find Alex.ser
class being created.
Now lets deserialize the object. We will create a class StudentDeserialize.java
StudentDeserialize.java
import com.protobufdemo.models.Student;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class StudentDeserialize
{
public static void main(String[] args) throws IOException {
// Get the file path
Path path = Paths.get("Alex.ser");
// Read the bytes from the file
byte[] bytes = Files.readAllBytes(path);
// Create the student object from the bytes
Student deserializedAlex = Student
.parseFrom(bytes);
System.out.println(deserializedAlex);
}
}
Run the main()
method of StudentDeserialize.java
class
Console output (StudentDeserialize.java)
name: "Alex"
age: 20
Look how we were able to serialize and deserialize java object using protocol buffers.
Let us see how we can create objects involving composition
. We will add an address field
in the Student object and therefore create a separate proto file for Address.
address.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.protobufdemo.models";
message Address {
string street = 1;
string city = 2;
string pincode = 3;
}
Now, we will update the student.proto
file
student.proto
syntax = "proto3";
import "address.proto";
option java_multiple_files = true;
option java_package = "com.protobufdemo.models";
message Student {
string name = 1;
int32 age = 2;
Address address = 3;
}
Now run the command
mvn clean install
and you will see updated generated classes for Address and Student classes;
Lets update our StudentDemo.java
class to include the address field.
StudentDemo.java
import com.protobufdemo.models.Address;
import com.protobufdemo.models.Student;
public class StudentDemo
{
public static void main(String[] args)
{
Address address = Address
.newBuilder()
.setStreet("street 1")
.setCity("city 1")
.setPincode("123456")
.build();
Student Alex = Student
.newBuilder()
.setName("Alex")
.setAddress(address)
.setAge(20)
.build();
System.out.println(Alex);
}
}
Run the main()
method of StudentDemo.java
class;
Console output (StudentDemo.java)
name: "Alex"
age: 20
address {
street: "street 1"
city: "city 1"
pincode: "123456"
}
This article explained how we can use Protocol Buffers to serialize and deserialize data in a language neutral, platform neutral extensible manner. For example , you can Serialize data from from one service using Java, and deserialize it on other service using C++ or JavaScript or any language that Protocol Buffers support if you have the same proto files on both the services.
The article provides a good introduction to Protocol Buffers with a small hands on example, and is best for beginners who are just starting out to learn Protocol Buffers.
I hope you found the article useful.
Lets connect :
Happy Coding :) .