I am migrating a java application from protocol buffers 2 to protocol buffer 3.
In proto 2 to check if a field is set you have hasfield()
method
for which an example Java code generated is:
public boolean hasText() {
return ((bitField0_ & 0x00000004) == 0x00000004);
}
However in proto 3 there it has been removed. How do you check if a field has been set in proto 3?
One of the suggested approaches is given here:
# NOTE: As of proto3, HasField() only works for message fields, not for
# singular (non-message) fields. First try to use HasField and
# if it fails (with a ValueError) we manually consult the fields.
try:
return message_pb.HasField(property_name)
except ValueError:
all_fields = set([field.name for field in message_pb._fields])
return property_name in all_fields
Also, from the same page:
In proto3, field presence for scalar fields simply doesn't exist. Your mental model for proto3 should be that it's a C++ or Go struct. For integers and strings, there is no such thing as being set or not, it always has a value. For submessages, it's a pointer to the submessage instance which can be NULL, that's why you can test presence for it.
I think the recommended approach, which is not ideal because of design decisions made in proto3, is to check standard values. You cannot explicitly check whether a field is set or not. As access to msg._fields
is not recommended as described here the only thing that is left is to check whether the field is set to its standard value:
if msg.textfield.isEmpty() {
//assume textfield is not set
}
The best suggestion I've seen for this in proto3 is to wrap your field in a singleton oneof. This will allow you to check for presence / absence again, similar to proto2.
message blah
{
oneof foo_ { sint32 foo = 1; }
}
In Python generated code this is extremely smooth as foo
can be directly operated on as a scalar as if it wasn't inside a oneof.
Unfortunately, for Java I think support for oneof's is far uglier. Google also purposely removed the hasFoo() generated class function in proto3. So you would need to consult the getFooCase() of the oneof instead to check for presence or absence.
https://developers.google.com/protocol-buffers/docs/reference/java-generated#oneof-fields
Yes, I realize these means tons of oneof's and any attendant hassle they bring. On the plus side, there is no overhead on the wire.
The second best suggestion I've seen is to use a submessage to wrap your scalar because presence / absence of submessages is still supported. There are the Well Known Types (WKT) in google.protobuf.wrappers.proto. If you use those, then you may even get extra special treatment in your preferred language where the wrapped scalar can be easily operated on as if the containing submessage didn't exist (or so I've read, not entirely sure on this point myself).
Protobuf 3.15.0 now has the support for optional fields. You can use hasField
methods again.
hasField()
I see some people are suggesting to use oneof
to wrap your field in it but proto3
already provides built-in wrappers
with hasField
kind of methods for primitive data types which will allow you to check if the field has been set or not.
This is how you can declare it (see more Value types here):
syntax = "proto3";
import "google/protobuf/wrappers.proto";
message MyProtoMessage {
google.protobuf.BoolValue enabled = 1;
google.protobuf.StringValue name = 2;
google.protobuf.Int32Value age = 3;
}
and this in Java code to check it:
MyProtoMessage myProtoMessage = getItFromSomewhere();
if (myProtoMessage.hasName()) {
// field is set by client
myProtoMessage.getName();
} else {
// field is not set by the client
// but you can still call `myProtoMessage.getName()` which will `return` default value ""
}
User contributions licensed under CC BY-SA 3.0