Json vs Proto -Performance Comparison

Aksshar Ramesh
5 min readFeb 3, 2021

In the previous article i have mentioned that protobuf is light faster than JSON. And it’s great for inter microservices communication. So in this article, what we are going to do is that we are going to do a simple performance test between protobuf and JSON. And see whether protobuf is really faster.

In order to check the performance we need to create a maven project. So that i am using IntelliJ, you can use any other IDE like STS or Eclipse.

Go to File -> New -> Project and create a maven project with a suitable name.

Click Next
Provide a Name and Click Finish

After creating the project you need to insert some dependencies and plugins for supporting protobuf.

Open your pom.xml file and insert these code right before closing tag of </project>.

<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.32.1</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>
</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>1.8</source>
<target>1.8</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.6.1:exe:${os.detected.classifier}
</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>
io.grpc:protoc-gen-grpc-java:1.22.1: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>
</plugins>
</build>

After Inserting these we need to load the maven changes. To do that press CTRL+SHIFT+O.

After the loading finished, next you need to create a directory named proto under the src -> main.

create a proto file named Book.proto inside the proto directory. Since we are using proto version three, we need to define some options at the beginning of the proto file which defines the proto version and the package for keeping the generated class files for proto. you can change package name as you decide.

syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.protoJsonComp.models";

let’s create our message for book.

message Book{
string name = 1;
int32 year = 2;
}

you can learn more about how to work with the proto files from my previous article -> protocol Buffers.

When your working with proto files you need compile the maven profile for each changes in the proto file. Unless it will not change the classes automatically. Go to maven panel at the right side of the project window and your project -> Lifecycle -> compile.

Click compile

after that we need to create class for comparing JSON. For that create a Jbook.java class inside src ->main ->java -> json ->Jbook.java. create fields with getters and setters.

public class Jbook {
private String name;
private int year;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getYear() {
return year;
}

public void setYear(int year) {
this.year = year;
}
}

create one more package named protobuf inside src->main->java->protobuf and create a class PerformanceTest.java to do testing.

In order to perform testing we need to create two runnables. before that lets create the Jbook object inside the main function.

import json.Jbook;

public class PerformanceTest {
public static void main(String[] args) {

Jbook jbook = new Jbook();
jbook.setName("Jungle Stories");
jbook.setYear(1996);

}
}

Next we need to serialize and deserialize this object. We can use object for this.create a mapper object. for that we need to insert one more dependency in the pom.xml file.

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>

lets create the mapper object. Don’t forget to import.

ObjectMapper mapper = new ObjectMapper();

Now we can serialize and deserialize the jbook object inside the runnable. I am using the Lambda Expressions here.

Runnable runnable =() ->{
try {
byte[] bytes = mapper.writeValueAsBytes(jbook);
Jbook jbook1 = mapper.readValue(bytes,Jbook.class);
} catch (IOException e) {
e.printStackTrace();
}
};

similarly lets do this for the Book protobuf also.

//protobuf
Book
book = Book.newBuilder()
.setName("Jungle Stories")
.setYear(1996)
.build();

Runnable runnableProtobuf = () ->{
try {
byte[] bytes = book.toByteArray();
Book book1 = Book.parseFrom(bytes);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
};

So we have created the runnables for each. Now lets create function for Testing the performance.

public static void runPerformanceTest(Runnable runnable,String method){
long timeStart = System.currentTimeMillis();
for (int i = 0;i < 1_000_000;i++){
runnable.run();
}
long timeFinish = System.currentTimeMillis();
System.out.println(method+" = "+(timeFinish - timeStart)+" ms ");
}

here i am passing the runnable and methode type and calculating the initial time before run and performing the run operation 1_000_000 times and after that printing the calculated time which it takes to run in ms.

Ok we almost done. lets call the runPerformanceTest() function from main class.

runPerformanceTest(runnableJson,"Json");
runPerformanceTest(runnableProtobuf,"Protobuf");

we have came through too many steps So i have showed the entire code for the file below.

package protobuf;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.InvalidProtocolBufferException;
import com.protoJsonComp.models.Book;
import json.Jbook;

import java.io.IOException;

public class PerformanceTest {
public static void main(String[] args) {

Jbook jbook = new Jbook();
jbook.setName("Jungle Stories");
jbook.setYear(1996);

ObjectMapper mapper = new ObjectMapper();

//JSON
Runnable
runnableJson = () ->{
try {
byte[] bytes = mapper.writeValueAsBytes(jbook);
Jbook jbook1 = mapper.readValue(bytes,Jbook.class);
} catch (IOException e) {
e.printStackTrace();
}
};

//protobuf
Book
book = Book.newBuilder()
.setName("Jungle Stories")
.setYear(1996)
.build();

Runnable runnableProtobuf = () ->{
try {
byte[] bytes = book.toByteArray();
Book book1 = Book.parseFrom(bytes);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
};

runPerformanceTest(runnableJson,"Json");
runPerformanceTest(runnableProtobuf,"Protobuf");
}

public static void runPerformanceTest(Runnable runnable,String method){
long timeStart = System.currentTimeMillis();
for (int i = 0;i < 1_000_000;i++){
runnable.run();
}
long timeFinish = System.currentTimeMillis();
System.out.println(method+" = "+(timeFinish - timeStart)+" ms ");
}
}

Let’s run the file and see the results……………..

Right Click -> Run PerformanceTest.main()

So you can see the output like above. look how the speed difference is. Try to run more times and see the output.

thank you.

--

--

Aksshar Ramesh

AI Security Research fellow at Centre for Sustainable Cyber Security, University of Greenwich