why protobuf optional field does not take null

24,174 views
Skip to first unread message

micha

unread,
Oct 29, 2009, 5:47:51 AM10/29/09
to Protocol Buffers
Hi,

I have a message with a optionl field.

* optional string param_country = 6;

I would like to avoid the to check each attribute if its null or not,
before setting it to the message.

In the net i found some code fragment of protobuf, that looked to me
that setting this field to null

* .setParamCountry(someNullReference)

makes the Builder to call clearParamCountry().




But I get a NullPoiterException ....

Kenton Varda

unread,
Oct 29, 2009, 2:29:44 PM10/29/09
to micha, Protocol Buffers
Protocol buffers has no concept of null.  Fields cannot be set to null.  You can *clear* a field, like:

  builder.clearParamCountry();

This sets the field back to its default value (the empty string, unless you declared some other default).  Also, hasParamCountry() will return false until you set it to something else.

But you cannot set any field to null -- this will throw a NullPointerException.

dp

unread,
Nov 30, 2009, 6:16:55 PM11/30/09
to Protocol Buffers
Is this still true? Or is there some way to tell PB that a field can
potentially have null values?

If not, any suggestions on how to deal with fields that could
potentially have null values? (Besides the obvious - don't set them,
d'oh)

*Asking 'cuz I have a fairly big class (~100 fields) and testing if
each field is null before setting them in the PB Builder object is
somewhat of a pain.

Henner Zeller

unread,
Nov 30, 2009, 6:42:24 PM11/30/09
to dp, Protocol Buffers
Hi,
On Mon, Nov 30, 2009 at 15:16, dp <decimus...@gmail.com> wrote:
> Is this still true? Or is there some way to tell PB that a field can
> potentially have null values?

No change here.

Problem is that 'null' and 'cleared' are semantically different things.
Sometimes in the software world they're used to mean the same thing
but protocol buffers shouldn't follow that, because that notion is not
universal if you think platform independently. In C++ for instance,
you won't deal with a 'NULL' string (unlike Java, no pointers, pardon,
references are used there).
Note, that protocol buffers have as well the notion of 'default
values'. So if you set a field to 'null' but meaning to clear it, then
accessing that field will return the default value. This is confusing
at best.

Given this and the platform independent notion I think it is better to
be explicit and not have 'null' magically meaning clearing a field.

> If not, any suggestions on how to deal with fields that could
> potentially have null values? (Besides the obvious - don't set them,
> d'oh)
>
> *Asking 'cuz I have a fairly big class (~100 fields) and testing if
> each field is null before setting them in the PB Builder object is
> somewhat of a pain.

A one-line if (foo != null) b.setFoo(foo) else b.clearFoo(); might be
a bit cluttersome sometimes. OTOH, it is pretty straightforward and
quick to read.

Maybe you can hack up some dynamic proxy that wraps around the setters
(haven't done Java for some time, probably this only works with
interfaces). Or alternatively you chaneg the higher level logic to
just _not_ set a field instead of setting it to 'null' when it really
means that it doesn't want to set it ...

-h

>
> On Oct 29, 10:29 am, Kenton Varda <ken...@google.com> wrote:
>> Protocol buffers has no concept of null.  Fields cannot be set to null.  You
>> can *clear* a field, like:
>>
>>   builder.clearParamCountry();
>>
>> This sets the field back to its default value (the empty string, unless you
>> declared some other default).  Also, hasParamCountry() will return false
>> until you set it to something else.
>>
>> But you cannot set any field to null -- this will throw a
>> NullPointerException.
>>
>>
>>
>> On Thu, Oct 29, 2009 at 2:47 AM, micha <mherttr...@googlemail.com> wrote:
>>
>> > Hi,
>>
>> > I have a message with a optionl field.
>>
>> > *  optional string param_country = 6;
>>
>> > I would like to avoid the to check each attribute if its null or not,
>> > before setting it to the message.
>>
>> > In the net i found some code fragment of protobuf, that looked to me
>> > that setting this field to null
>>
>> > *  .setParamCountry(someNullReference)
>>
>> > makes the Builder to call clearParamCountry().
>>
>> > But I get a NullPoiterException ....
>
> --
>
> You received this message because you are subscribed to the Google Groups "Protocol Buffers" group.
> To post to this group, send email to prot...@googlegroups.com.
> To unsubscribe from this group, send email to protobuf+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/protobuf?hl=en.
>
>
>

Kenton Varda

unread,
Nov 30, 2009, 8:34:26 PM11/30/09
to Henner Zeller, dp, Protocol Buffers
I'm still open to the idea of adding setOrClearFoo() methods that clear the value if given null -- but only if it can be shown that this will not significantly increase the size of compiled .class files.

Subin Sebastian

unread,
Mar 20, 2017, 7:53:43 AM3/20/17
to Protocol Buffers, henner...@googlemail.com, decimus...@gmail.com
8 years later, still the only solution I have is,

class MyImprovedClass extends MyClass { // MyClass is protoc generated
    public void setOrClearFoo(String value) {
        if(value != null) setFoo(value);
        else clearFoo();

Josh Humphries

unread,
Mar 20, 2017, 9:34:33 AM3/20/17
to Subin Sebastian, Protocol Buffers, henner...@googlemail.com, decimus...@gmail.com
In a past life, we used a protoc plugin that just added these setOrClear* to every builder for each non-repeated field (as well as getOrNull* methods for every message). The standard generated java code has insertion points that make this a fairly trivial plugin to write. We also experimented with adding extra accessors/setters using Guava's Optional (and would probably use Java 8's Optional today), but that just exploded the API too much.

The generated code is already so voluminous! Adding more and more cruft to every generated proto wasn't awesome. However, I do agree that the setOrClear* class of methods was the most useful. Without them, you can't use method-chaining when building a message where one of the inputs you're conveying is nullable.

// Kind of stinky:
MyMessage.Builder b = MyMessage.newBuilder()
  .setFoo(foo)
  .setBar(bar)
  .setBaz(baz);
if (frobnitz != null) {
  b.setFrobnitz(frobnitz)
}
return b.build();


// Better:
return MyMessage.newBuilder()
  .setFoo(foo)
  .setBar(bar)
  .setBaz(baz)
  .setOrClearFrobnitz(frobnitz)
  .build();


----
Josh Humphries
jh...@bluegosling.com

To unsubscribe from this group and stop receiving emails from it, send an email to protobuf+unsubscribe@googlegroups.com.

To post to this group, send email to prot...@googlegroups.com.

Louis Cognault

unread,
Apr 22, 2017, 2:27:21 PM4/22/17
to Protocol Buffers, henner...@googlemail.com, decimus...@gmail.com
Or you can use extension functions in Kotlin ;)

wanda mcmurray

unread,
May 8, 2017, 4:59:34 AM5/8/17
to Protocol Buffers
Reply all
Reply to author
Forward
0 new messages