mah454
mah454

Reputation: 1919

Google Protobuf handle null values

somebody explain me how can handle null values in google protobuf .
i have structure like this :

syntax = "proto3";
import "google/protobuf/wrappers.proto";
message Person {
  google.protobuf.DoubleValue age = 4;
}     

and java code :

DoubleValue myAge = null;
Person build = Person.newBuilder()
                .setAge(myAge)  // <- NPE
                .build();

this code result null pointer exception on .setAge(myAge) line.
so what is use case of protobuf DoubleValue ? I thought it was used to manage null values . but still receive NullPointerException .

Do you use code like this for handle this problem ?

DoubleValue a = null;
Person.Builder builder = Person.newBuilder();
if (a != null) {
    builder.setAge(a);
}

Person build = builder.build();     

UPDATE:
this is part of code generated by protoc command :

/**
* <code>.google.protobuf.DoubleValue age = 9;</code>
*/
public Builder setAge(com.google.protobuf.DoubleValue value) {
if (ageBuilder_ == null) {
    if (value == null) {        //<-- Additional statement
        throw new NullPointerException();
    }
    age_ = value;
    onChanged();
} else {
    ageBuilder_.setMessage(value);
}   

Why set additional if statement in generated code ?
I think this is a bug for google protocol buffer.
finally i wrote this code:

DoubleValue.Builder builder = DoubleValue.newBuilder();
DoubleValue myAge = null;
Person build = Person.newBuilder()
                .setAge(myAge != null ? myAge : builder )
                .build();

Upvotes: 5

Views: 11526

Answers (2)

Tushar Pandey
Tushar Pandey

Reputation: 550

For dart you can set it as:

DoubleValue(value: null)

Upvotes: 0

Rafael Lerm
Rafael Lerm

Reputation: 1400

DoubleValue is meant to handle missing values, not necessarily null. Protobuf libraries are intended to never involve nulls - for example, it never returns null, even for missing fields. Also, as you've found out, setters don't accept null. For example, to clear a field you'd use clearField instead of setField(null).

One of the big differences between proto2 and proto3 is that (initially) "hazzers" for primitive fields (e.g. hasField) were removed. That is, if you have a double my_field, there is no way to tell if it was never set, or set explicitly to zero. getMyField() would return 0 in both cases.

Note that messages still have hazzers, so if you want that functionality, you could wrap your primitive field in a message. Which is exactly what DoubleValue is. So if you have a field DoubleValue age = 1, you could use hasAge() to determine if it's set. In newer protobuf version, you could do the same with optional double age = 1.

Note that all of this has no relation with null in the Java generated code. There really is no way a setter would accept a null value.

TL;DR: Your first suggestion is good and very common:

DoubleValue a = null;
Person.Builder builder = Person.newBuilder();
if (a != null) {
    builder.setAge(a);
}
Person build = builder.build();     

If instead of null you have an Optional, you could use a similar variant:

OptionalDouble a = OptionalDouble.empty();
Person.Builder builder = Person.newBuilder();
a.ifPresent(value-> builder.getAgeBuilder().setValue(value));

Person build = builder.build();

Upvotes: 3

Related Questions