Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling null values in protobuffers

I am working on something which fetches data from database and constructs protobuff message. Given the possibility that null values can be fetched from the database for certain fields , I will get Null-pointer exception while trying to construct the protobuff message. Getting to know that null is not supported in protobuffs from the thread http://code.google.com/p/protobuf/issues/detail?id=57, I am wondering whether the only other way to handle NPE getting thrown is to insert manual checks into the java file corresponding to the proto like below!

message ProtoPerson{     optional string firstName = 1;     optional string lastName = 2;     optional string address1 = 3; }  ProtoPerson.Builder builder = ProtoPerson.Builder.newBuilder(); if (p.getFirstName() != null) builder.setFirstName(p.getFirstName()); if (p.getLastName() != null) builder.setLastName(p.getLastName()); if (p.getAddress1() != null) builder.setAddress1(p.getAddress1()); ... 

So can someone please clarify whether there is any other possible efficient way to handle the null values during protobuff construction??

like image 849
Aarish Ramesh Avatar asked Jan 20 '14 06:01

Aarish Ramesh


People also ask

How do I allow null values in Protobuf?

Protobuf treats strings as primitive types and therefore they can not be null. Instead of checking if the string is not null use standard libraries, like apache commons, to check if the string is not blank. This is clear that the value will be inserted if the value is not blank.

How do I set default value in Protobuf?

For bool s, the default value is false. For numeric types, the default value is zero. For enums , the default value is the first value listed in the enum's type definition. This means care must be taken when adding a value to the beginning of an enum value list.

What is Google Protobuf empty?

protobuf. Empty states: A generic empty message that you can re-use to avoid defining duplicated empty messages in your APIs. A typical example is to use it as the request or the response type of an API method.


1 Answers

Disclaimer: Answer from a Googler using protobufs on a daily basis. I'm by no means representing Google in any way.

  1. Name your proto Person instead of PersonProto or ProtoPerson. Compiled protobufs are just class definitions specified by the language you are using, with some improvements. Adding "Proto" is extra verbosity.
  2. Use YourMessage.hasYourField() instead of YourMessage.getYourField() != null. Default value for protobuf string is an empty string, which does NOT equal to null. Whereas, no matter whether your field is unset or cleared or empty string, .hasYourField() always returns false. See default values for common protobuf field types.
  3. You've probably known, but I wanna say explicitly: Don't programmatically set a protobuf field to null. Even for outside of protobuf, null causes all sorts of problems. Use .clearYourField() instead.
  4. Person.Builder class does NOT have a .newBuilder() method. Person class does. Understand the Builder Pattern like this: You create a new builder only if you do not have it yet.

A rewrite of your protobuf:

message Person {   optional string first_name = 1;   optional string last_name = 2;   optional string address_1 = 3; } 

A rewrite of your logic:

Person thatPerson = Person.newBuilder()     .setFirstName("Aaa")     .setLastName("Bbb")     .setAddress1("Ccc")     .build();  Person.Builder thisPersonBuilder = Person.newBuilder()  if (thatPerson.hasFirstName()) {   thisPersonBuilder.setFirstName(thatPerson.getFirstName()); }  if (thatPerson.hasLastName()) {   thisPersonBuilder.setLastName(thatPerson.getLastName()); }  if (thatPerson.hasAddress1()) {   thisPersonBuilder.setAddress1(thatPerson.getAddress1()); }  Person thisPerson = thisPersonBuilder.build(); 

And if thatPerson is a person object that you created that has attribute values that could be an empty string, empty spaces or null, then I'd recommend using Guava's Strings library:

import static com.google.common.base.Strings.nullToEmpty;  Person.Builder thisPersonBuilder = Person.newBuilder()  if (!nullToEmpty(thatPerson.getFirstName()).trim().isEmpty()) {   thisPersonBuilder.setFirstName(thatPerson.getFirstName()); }  if (!nullToEmpty(thatPerson.hasLastName()).trim().isEmpty()) {   thisPersonBuilder.setLastName(thatPerson.getLastName()); }  if (!nullToEmpty(thatPerson.hasAddress1()).trim().isEmpty()) {   thisPersonBuilder.setAddress1(thatPerson.getAddress1()); }  Person thisPerson = thisPersonBuilder.build(); 
like image 56
Michael Xin Sun Avatar answered Sep 22 '22 15:09

Michael Xin Sun