How to define an optional field in protobuf 3

I need to specify a message with an optional field in protobuf (proto3 syntax). In terms of proto 2 syntax, the message I want to express looks something like this:

message Foo { required int32 bar = 1; optional int32 baz = 2; } 

From my understanding, the β€œoptional” concept has been removed from the proto 3 syntax (along with the necessary concept). Although the alternative is unclear - using the default value to indicate that the field was not specified by the sender leaves uncertainty if the default value belongs to the domain of valid values ​​(consider, for example, the Boolean type).

So how should I encode the message above? Thanks.

+55
source share
6 answers

In proto3, all fields are "optional" (if the sender cannot specify them). But the fields are no longer β€œnullable” since there is no way to tell the difference between a field that has a default value explicitly set and one that has not been set at all.

If you need the "null" state (and there is no value out of range that you can use for this), you will need to encode this as a separate field instead. For example, you can do:

 message Foo { bool has_baz = 1; // always set this to "true" when using baz int32 baz = 2; } 

Alternatively, you can use oneof :

 message Foo { oneof baz { bool baz_null = 1; // always set this to "true" when null int32 baz_value = 2; } } 

The oneof version is more explicit and more efficient on the web, but requires an understanding of how oneof values oneof .

Finally, another perfectly reasonable option is to stick with proto2. Proto2 is not outdated, and in fact, many projects (including those inside Google) are very dependent on proto2 functions that are removed in proto3, so they probably will never switch. Thus, it is safe to use it for the foreseeable future.

+75
source

One way is to use oneof as suggested in the accepted answer.

Another way is to use wrapper objects. You do not need to write them yourself, as Google already provides them:

At the top of the .proto file, add this import:

import "google/protobuf/wrappers.proto";

Now you can use special wrappers for each simple type:

 DoubleValue FloatValue Int64Value UInt64Value Int32Value UInt32Value BoolValue StringValue BytesValue 

Therefore, to answer the initial question, the use of such a wrapper could be like this:

 message Foo { int32 bar = 1; google.protobuf.Int32Value baz = 2; } 

Now, for example, in Java, I can do things like:

if(foo.hasBaz()) { ... }

+50
source

Based on Kenton's answer, a simpler yet working solution is as follows:

 message Foo { oneof optional_baz { // "optional_" prefix here just serves as an indicator, not keyword in proto2 int32 baz = 1; } } 
+16
source

Read more about @cybersnoopy offer here

if you had a .proto file with this message:

 message Request { oneof option { int64 option_value = 1; } } 

You can use case parameters (code generated by Java) :

Now we can write some code as follows:

 Request.OptionCase optionCase = request.getOptionCase(); OptionCase optionNotSet = OPTION_NOT_SET; if (optionNotSet.equals(optionCase)){ // value not set } else { // value set } 
+4
source

You can find out if it was initialized by comparing the links with the default instance:

 GRPCContainer container = myGrpcResponseBean.getContainer(); if (container.getDefaultInstanceForType() != container) { ... } 
0
source

Another way is that you can use a bitmask for each optional field. and set these bits if values ​​are set, and discard those bits whose values ​​are not set

 enum bitsV { baz_present = 1; // 0x01 baz1_present = 2; // 0x02 } message Foo { uint32 bitMask; required int32 bar = 1; optional int32 baz = 2; optional int32 baz1 = 3; } 

When parsing, check the value of bitMask.

 if (bitMask & baz_present) baz is present if (bitMask & baz1_present) baz1 is present 
0
source

Source: https://habr.com/ru/post/986288/


All Articles