Reputation: 1919
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
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