-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistency in handling of oneof fields in encode and fromObject and toObject #710
Comments
The safe way here is to always use However, I am also not yet satisfied with the API - there are three possible scenarios:
Currently, I'd favor option 2 as a compromise. This however assumes that plain objects (usually) don't have multiple fields of the same oneof set at once. Virtual getters could still remain. |
With this in place, your specific use case should be working - but the following isn't covered anymore: OneOfMessage.encode({
first: 1,
second: "a"
}); This will now encode both values on the wire. The receiving part, however, will omit all but the last. When using runtime messages instead, virtual setters will still clear all but the last. |
I'm not an expert on oneof encoding/decoding but it seems like protobuf should never include more than one oneof field/value on the wire. The Java API for example will automatically clear the 'first' field/value if the 'second' field/value is set. Protobuf could match this behavior in the OneOfMessage.encode method by clearing the previous set oneof field when a new oneof is found. Not sure if the order of encode is deterministic or not so encode results may not be consistent. My other comment is the JSON is invalid input based on the .proto definition for a OneOfMessage. encode could report an error when it encounters more than one 'oneof' field. My first suggest is just to send the 'last' oneof field during the encode method. Just my two cents.... |
Why isn't And, in any case, it would still be useful for that virtual property to be present in the output of switch(value.choice) {
case 'first': // use value.first
case 'second': //use value.second
} And, because ProtoBuf.js 5 does output that virtual property, and gRPC uses Even if it was just another option in |
The sole reason why all those methods exist in the first place is performance. Each method does one thing, depending on what the user requires. For example, you could call
I am fine with that, going to implement.
Since 6.7.0 it is deterministic, encoding fields in ascending field id order (as of the spec).
This is actually missing in |
OK, if |
I have noticed something else closely related: if a message has a |
This should fix your latest issue. I also added more information regarding the intended use of the various methods to the README. Let me know if there is anything else left I can help with. Otherwise, I am also ready to push a release now. |
I don't know of any other issues. Thank you for the quick turnaround on these changes. |
Should be fixed in master. Feel free to reopen if there are any remaining issues! |
Can you publish these changes soon? |
It's now on npm as 6.7.0. |
The verifier seems to return the error about multiple fields being set unconditionally. The following code illustrates this // oneof.proto
syntax = "proto3";
message OneOfValues {
oneof oneof_choice {
int32 int_choice = 1;
string string_choice = 2;
}
} In the following code, each protobuf.load("oneof.proto", function(err, root) {
var OneOfValues = root.lookupType('OneOfValues');
console.log(OneOfValues.verify(OneOfValues.fromObject({})));
console.log(OneOfValues.verify(OneOfValues.fromObject({int_choice: 5})));
console.log(OneOfValues.verify(OneOfValues.fromObject({oneof_choice: 'int_choice', int_choice: 5})));
console.log(OneOfValues.verify(OneOfValues.fromObject({string_choice: 'abc'})));
console.log(OneOfValues.verify(OneOfValues.fromObject({oneof_choice: 'string_choice', string_choice: 'abc'})));
}); |
Currently, OneOfValues.verify(OneOfValues.fromObject({}))
// should be:
OneOfValues.verify({}) But now that you mentioned it I see that there are a couple of issues arising from this. Going to look into it. The underlying issue probably is that encoders check for |
protobuf.js version: 6.6.5
When encoding a plain object representing a message with a
oneof
field, the field containing the value will be ignored will be ignored unless there is an additional object member with which is the name of theoneof
field mapping to the string name of the field chosen. But that additional object member is not required when usingfromObject
, or emitted bytoObject
.In addition, in ProtoBuf.js 5, that additional object member was always emitted by the
toObject
equivalent, and that was very convenient for use inswitch
statements. My preferred solution here would be to always emit that field member intoObject
.I think the most important thing to note is that encoding and decoding
value1
twice gives a different result than doing so just once.The text was updated successfully, but these errors were encountered: