March 27, 2023

In a world of microservices, we regularly should cross info between purposes. We serialize information right into a format that may be retrieved by each side. One of many serialization options is Protocol Buffers (Protobuf) – Google’s language-neutral mechanism. Messages might be interpreted by a receiver utilizing the identical or totally different language than a producer. Many languages are supported, reminiscent of Java, Go, Python, and C++.

A knowledge construction is outlined utilizing impartial language by means of .proto recordsdata. The file is then compiled into code for use in purposes. It’s designed for efficiency. Protocol Buffers encode information into binary format, which reduces message dimension and improves transmission velocity.

Defining Message Format

This .proto the file represents geolocation info for a given car.

1 syntax = "proto3";
3 package deal com.grapeup.geolocation;
5 import "google/kind/latlng.proto";
6 import "google/protobuf/timestamp.proto";
8 message Geolocation 
9  string vin = 1;
10  google.protobuf.Timestamp occurredOn = 2;
11  int32 velocity = 3;
12  google.kind.LatLng coordinates = 4;
1 syntax = "proto3";

Syntax refers to Protobuf model, it may be proto2 or proto3.

1package com.grapeup.geolocation;

Bundle declaration prevents naming conflicts between totally different tasks.

1 message Geolocation 
2  string vin = 1;
3  google.protobuf.Timestamp occurredOn = 2;
4  int32 velocity = 3;
5  google.kind.LatLng coordinates = 4;

Message definition accommodates a reputation and a set of typed fields. Easy information varieties can be found, reminiscent of bool, int32, double, string, and so forth. You too can outline your individual varieties or import them.

1google.protobuf.Timestamp occurredOn = 2;

The = 1, = 2 markers determine the distinctive tag. Tags are a numeric illustration for the sector and are used to determine the sector within the message binary format. They should be distinctive in a message and shouldn’t be modified as soon as the message is in use. If a subject is faraway from a definition that’s already used, it should be reserved.

Subject varieties

Apart from scalar varieties, there are a lot of different kind choices when defining messages. Listed below are few, however yow will discover all of them within the Language Information Language Guide (proto3)  |  Protocol Buffers  |  Google Developers .

Effectively Recognized Sorts

1 import "google/kind/latlng.proto";
2 import "google/protobuf/timestamp.proto";
4 google.protobuf.Timestamp occurredOn = 2;
5 google.kind.LatLng coordinates = 4;

There are predefined varieties obtainable to make use of Overview  |  Protocol Buffers  |  Google Developers . They’re often known as Effectively Know Sorts and should be imported into .proto .

LatLng represents a latitude and longitude pair.

Timestamp is a selected time limit with nanosecond precision.

Customized varieties

1 message SingularSearchResponse 
2  Geolocation geolocation = 1;

You should use your custom-defined kind as a subject in one other message definition.


1 message SearchResponse 
2  repeated Geolocation geolocations = 1;

You’ll be able to outline lists by utilizing repeated key phrase.


It might occur that in a message there’ll at all times be just one subject set. On this case, TelemetryUpdate will comprise both geolocation, mileage, or gasoline degree info.

This may be achieved by utilizing oneof. Setting worth to one of many fields will clear all different fields outlined in oneof.

1 message TelemetryUpdate 
2  string vin = 1;
3  oneof replace 
4    Geolocation geolocation = 2;
5    Mileage mileage =3;
6    FuelLevel fuelLevel = 4;
10 message Geolocation 
11  ...
14 message Mileage 
15  ...
18 message FuelLevel 
19  ...

Take into accout backward-compatibility when eradicating fields. If you happen to obtain a message with oneof that has been faraway from .proto definition, it won’t set any of the values. This conduct is identical as not setting any worth within the first place.

You’ll be able to carry out totally different actions primarily based on which worth is ready utilizing the getUpdateCase() technique.

1 public Non-compulsory<Object> getTelemetry(TelemetryUpdate telemetryUpdate) 
2        Non-compulsory<Object> telemetry = Non-compulsory.empty();
3        swap (telemetryUpdate.getUpdateCase()) 
4            case MILEAGE -> telemetry = Non-compulsory.of(telemetryUpdate.getMileage());
5            case FUELLEVEL -> telemetry = Non-compulsory.of(telemetryUpdate.getFuelLevel());
6            case GEOLOCATION -> telemetry = Non-compulsory.of(telemetryUpdate.getGeolocation());
7            case UPDATE_NOT_SET -> telemetry = Non-compulsory.empty();
9        return telemetry;

Default values

In proto3 format fields will at all times have a worth. Because of this proto3 can have a smaller dimension as a result of fields with default values are omitted from payload. Nevertheless this causes one difficulty – for scalar message fields, there isn’t any method of telling if a subject was explicitly set to the default worth or not set in any respect.

In our instance, velocity is an non-obligatory subject – some modules in a automobile may ship velocity information, and a few won’t. If we don’t set velocity, then the geolocation object can have velocity with the default worth set to 0. This isn’t the identical as not having velocity set on messages.

As a way to cope with default values you should use official wrapper varieties protobuf/wrappers.proto at main · protocolbuffers/protobuf . They permit distinguishing between absence and default. As an alternative of getting a easy kind, we use Int32Value, which is a wrapper for the int32 scalar kind.

1 import "google/protobuf/wrappers.proto";
3 message Geolocation 
4  google.protobuf.Int32Value velocity = 3;

If we don’t present velocity, it will likely be set to nil.

Configure with Gradle

When you’ve outlined your messages, you should use protoc, a protocol buffer compiler, to generate lessons in a selected language. The generated class can then be used to construct and retrieve messages.

As a way to compile into Java code, we have to add dependency and plugin in construct.gradle

1 plugins 
2    id '' model '0.8.18'
5 dependencies 
6    implementation ''

and setup the compiler. For Mac customers an osx particular model must be used.

1 protobuf 
2    protoc 
3        if (osdetector.os == "osx") 
4            artifact = "$protobuf_version:osx-x86_64"
5         else 
6            artifact = "$protobuf_version"

Code might be generated utilizing generateProto process.

The code might be situated in construct/generated/supply/proto/most important/java in a package deal as laid out in .proto file.

We additionally want to inform gradle the place the generated code is situated

1 sourceSets 
2    most important 
3        java 
4            srcDirs 'construct/generated/supply/proto/most important/grpc'
5            srcDirs 'construct/generated/supply/proto/most important/java'

The generated class accommodates all the mandatory strategies for constructing the message in addition to retrieving subject values.

1 Geolocation geolocation = Geolocation.newBuilder()
2            .setCoordinates(LatLng.newBuilder().setLatitude(1.2).setLongitude(1.2).construct())
3            .setVin("1G2NF12FX2C129610")
4            .setOccurredOn(Timestamp.newBuilder().setSeconds(12349023).construct())
5            .construct();
7 LatLng coordinates = geolocation.getCoordinates();
8 String vin = geolocation.getVin();

Protocol Buffers – Abstract

As proven protocol buffers are simply configured. The mechanism is language agnostic, and it’s simple to share the identical .proto definition throughout totally different microservices.

Protobuf is well paired with gRPC, the place strategies might be outlined in .proto recordsdata and generated with gradle.

There’s official documentation obtainable Protocol Buffers  |  Google Developers and guides Language Guide (proto3)  |  Protocol Buffers  |  Google Developers .