Protocol buffer — Custom options

Harsh Mishra
3 min readFeb 23, 2021

In the previous article, I had introduced a little bit about the GCP protocol buffer. In this article, we will touch upon the custom options for enum i.e.
EnumValueOptions

Protocol Buffer allows you to add the description in form of a descriptor and a descriptor even allow you to define and use your own options. Defining an option is simply a matter of extending those messages.

Why!!! An Abbreviation for example sometimes tricky to understand, So how would you enable another developer to understand the meaning of your enum values or consumer of message.

Like Algeria country code is DZ(alpha-2 code). Which is impossible to understand without having a knowledge, in this case a descriptor of enum would be helpful.

syntax = "proto3";
package com.protobuf.package;
import "common_proto.proto";
import "google/protobuf/descriptor.proto";
option java_package = "com.protobuf.package";
option java_outer_classname = "ProtoMessage";


extend google.protobuf.EnumValueOptions {
string indicator_country_value_option = 101;
}
message payload {
string uuid_id = 1;
int64 amount = 2;
bool feePayed = 3;
COUNTRY_CODE country= 4;
}

enum COUNTRY_CODE {

COUNTRY_CODE_UNKNOWN = 0;
COUNTRY_CODE_INDIA = 1 [(indicator_country_value_option) = "INR"];
COUNTRY_CODE_UNITED_KINGDOM = 2 [(indicator_country_value_option) = "GBR"];
COUNTRY_CODE_UNITED_STATE_OF_AMERICA = 3 [(indicator_country_value_option) = "USA"];

}

You can check the conventions, that will make your protocol buffer message definitions and their corresponding classes consistent and easy to read.

hmmm. So, now what, we have to create the proto object and publish it. right? but input will not come like this COUNTRY_CODE_INDIA from the rest api or from the external source of input.

It will be “INR” or “GBR”. So how to map it.

Similarly, While working with microservices/distributed services, The business use case of the consumer might be on the real value passed i.e. INR/GBR not on COUNTRY_CODE_INDIA. In order to solve it, they need to extract the value option from the Enum.

Good point!!! then how can we achieve it…..

let's take a look at the published code.

when input = “INR”

public ProtoMessage.COUNTRY_CODE getCountryProtoObject(String input){
Optional<Descriptors.EnumValueDescriptor> descriptorVal =
ProtoMessage.COUNTRY_CODE.getDescriptor()
.getValues().stream()
.filter(value -> input.equalsIgnoreCase(value.getOptions().getExtension(ProtoMessage.indicatorCountryValueOption)))
.findFirst();

return Optional.ofNullable(descriptorVal)
.map(descriptor - > ProtoMessage.COUNTRY_CODE
.forNumber(descriptor.get().getNumber()))
.orElse(ProtoMessage.COUNTRY_CODE.UNKNOWN_COUNTRY);
}

another way of doing the same thing

public ProtoMessage.COUNTRY_CODE getCountryProtoObject(String input){
ProtoMessage.COUNTRY_CODE country = ProtoMessage.COUNTRY_CODE.UNKNOWN_COUNTRY;
for (Descriptors.EnumValueDescriptor enumValueDescriptor: ProtoMessage.COUNTRY_CODE.getDescriptor().getValues())
{
String extension = enumValueDescriptor.getOptions()
.getExtension(ProtoMessage.indicatorCountryValueOption);
if(StringUtils.isNotBlank(input) && input.equals(extension)) {
country = ProtoMessage.COUNTRY_CODE
.forNumber(enumValueDescriptor.getNumber());
}
}
return country;
}

In both way output will be COUNTRY_CODE_INDIA for input “INR”

Ahh!!, We published it successfully

Hungry 😋!!! It’s time to consume the pubsub event message.

Consumer needs the value “INR” from the payload.COUNTRY_CODE object
to do so parse the pubsub message.

ProtoMessage.payload protoMessage = ProtoMessage.payload.parseFrom(basicAcknowledgeablePubsubMessage.getPubsubMessage().getData());

After parsing the message, get the country and assign it in the COUNTRY_CODE object.

ProtoMessage.COUNTRY_CODE countryProtoEnum = protoMessage.getPayload().getCountry();

Now, we have countryProtoEnum which consists the COUNTRY_CODE_INDIA.

It’s time to fetch the “INR” from this object

String country = countryProtoEnum.getValueDescriptor().getOptions().getExtension(ProtoMessage.indicatorCountryValueOption);

Now, we get the “INR” in-country variable.

So, We have seen how to publish and consume the correct enum values in the protocol buffer.

--

--