Set multiple fields as one element of oneof - protocol-buffers

I want to define a message that can have 2 fields (field A AND field B) XOR one other field (field C alone). I saw I can use the keyword oneof to set the XOR, but only between two fields.
how can I express my needs?
Ideally I want something like (not working)
syntax = "proto3";
message M {
oneof name {
{
string a = 1;
string b = 2;
}
string c = 3;
}
}

Only way I know of is to put the two fields a and b into separate submessage, which you can then put inside the oneof:
syntax = "proto3";
message A {
string a = 1;
string b = 2;
}
message M {
oneof name {
A a = 1;
string c = 3;
}
}
Alternatively you can put all fields into M without oneof. Describe the logic in the comments and check it manually in application code.

Related

Protobuf use repeated oneof message vs many empty fields

I'm designing a protobuf to represent an event, where each event can hold extra fields.
There are a lot of possible extra fields (~100), but only a small portion of them will be used in each message (~3)
Each extra field will be used only once, but multiple of them can exist, therefore I would like to have a concept of an anyof message type, but unfortunately, there is no such thing in protobuf.
So to try and mock this behavior, and as mentioned in this discussion I thought I can put all my extra fields in a oneof, wrap it with a message, and use this message as repeated in my event:
message ExtraField {
oneof extra_field_value {
string extraData1 = 1;
uint64 extraData2 = 2;
....
SomeOtherMessage extraData100 = 100;
}
}
message MyEvent {
uint64 timestamp = 1;
string event_name = 2;
string some_other_data = 3;
...
repeated ExtraField extra_fields = 8;
}
Even though this solution is more explicit for my understanding, it isn't the most memory effective, and the repeated message with oneof implementation allows to add the same extra field more than once (unwanted behavior)
I can also just write all the extra fields as-is in an inner message, but most of them will be empty all the time
message ExtraFields {
string extraData1 = 1;
uint64 extraData2 = 2;
....
SomeOtherMessage extraData100 = 100;
}
message MyEvent {
uint64 timestamp = 1;
string event_name = 2;
string some_other_data = 3;
...
extraFields extra_fields = 8;
}
If I understand correctly, using empty fields in a message isn't going to make my serialized data larger, and therefore the second protobuf design is the preferred practice
Am I correct?
Is there another protobuf design for my needs?

What the difference between google.protobuf.Any and google.protobuf.Value?

I want th serialize int/int64/double/float/uint32/uint64 into protobuf, which one should I use ? which one is more effective ?
For example :
message Test {
google.protobuf.Any any = 1; // solution 1
google.protobuf.Value value = 2; // solution 2
};
message Test { // solution 3
oneof Data {
uint32 int_value = 1;
double double_value = 2;
bytes string_value = 3;
...
};
};
In your case, you'd better use oneof.
You can not pack from or unpack to a built-in type, e.g. double, int32, int64, to google.protobuf.Any. Instead, you can only pack from or unpack to a message, i.e. a class derived from google::protobuf::Message.
google.protobuf.Value, in fact, is a wrapper on oneof:
message Value {
// The kind of value.
oneof kind {
// Represents a null value.
NullValue null_value = 1;
// Represents a double value.
double number_value = 2;
// Represents a string value.
string string_value = 3;
// Represents a boolean value.
bool bool_value = 4;
// Represents a structured value.
Struct struct_value = 5;
// Represents a repeated `Value`.
ListValue list_value = 6;
}
}
Also from the definition of google.protobuf.Value, you can see, that there's no int32, int64, or unint64 fields, but only a double field. IMHO (correct me, if I'm wrong), you might lose precision if the the integer is very large. Normally, google.protobuf.Value is used with google.protobuf.Struct. Check google/protobuf/struct.proto for detail.

What is the default value for an "other message type" in protobuf 2

I want to have a proto response with other message types as fields. I was hoping to only some of these fields and I was wondering what the default value will be if I don't set one of these fields.
The context is the "other message type" listed in https://developers.google.com/protocol-buffers/docs/proto#other
message SearchResponse {
optional Result1 result1 = 1;
optional Result1 result2 = 2;
}
message Result1 {
required string url = 1;
optional string title = 2;
repeated string snippets = 3;
}
message Result2 {
required string url2 = 1;
optional string title2 = 2;
repeated string snippets2 = 3;
}
For example, If I set result1 and not result2, would result2 by null or missing entirely or would result2 be present with the default values for all the strings?
Typically missing, in both proto2 and proto3 - bit it can depend a bit on whether your target platform has a concept of missing.
Consider: messages can be recursive. A Foo can have a Foo as a field. If it wasn't treated as missing, it would instantly explode.

Clear fields in a ProtobufMessage Java

I have a proto message of the following form defined:
message A {
message B {
message C {
optional string details = 1;
optional string time = 2;
}
repeated C c = 1;
}
repeated B b = 1;
}
and I want to write a java code to clear the field details from the object.
A a;
a.clearField(b.c.details);
NOTE that here b and c both are repeated fields.
Is there any way in which I can achieve this for Java protocol buffers?
Proto buffers are immutable, thus you can't edit A directly.
However you can achieve your goal with Proto builder. The code would look more-less like:
a = a.toBuilder()
.setB(
indexOfB,
a.getB(indexOfB).toBuilder()
.setC(
indexOfC,
a.getB(indexOfB).getC(indexOfC).toBuilder()
.clearDetails()
.build())
.build())
.build();

how to replace proto2 extension with proto3 any when extend different number of field?

I'm trying to learn proto3, and have some questions with any.
I use extension quite much, if my proto is like this:
message base {
extensions 1 to 100;
}
// a.proto
extend base {
optional int32 a = 1;
optional int32 b = 2;
}
// b.proto
extend base {
optional string c = 1;
optional string d = 2;
optional string e = 3;
optional string f = 4;
}
then how to replace these extensions with any ? should i must write like
import google/protobuf/any.proto
message base {
any a = 1;
any b = 2;
any c = 3;
any d = 4;
}
?
may so many proto has extended base.proto and I cannot make sure the max extension number of these protos. then how can I replace these extensions with any?
If I have to write any from 1 to 100 in message base ... oh, that will be too terrible !
You would typically structure it like this:
message base {
any submsg = 1;
}
// a.proto
message submsg_a {
optional int32 a = 1;
optional int32 b = 2;
}
// b.proto
message submsg_b {
optional string c = 1;
optional string d = 2;
optional string e = 3;
optional string f = 4;
}
And then put either submsg_a or submsg_b inside the any field.

Resources