我试图升级到使用protobuf版本3,并保持向后兼容版本2.似乎工作除了一件事 - 在proto-2中你可以设置你自己的默认值,但在原型3中,你不能。如果您在proto-2中选择的默认值不是proto-3中的标准默认值,那么您就遇到了问题。例如,在proto-2中:
message Record {
required uint32 fileno = 1;
required uint64 pos = 2;
optional uint64 bmsPos = 3 [default = 0];
optional uint32 scanMode = 4 [default = 9999];
}
现在在proto-3中必须是:
message Record {
uint32 fileno = 1;
uint64 pos = 2;
uint64 bmsPos = 3;
uint32 scanMode = 4;
}
在proto-2和proto-3中,消息中未发送缺失值。但是proto-3 API并没有告诉你默认值是否在消息中,它只是告诉你值。
因此proto-3接收器收到一条消息并告诉我scanMode = 0.如果该消息来自proto-2发送者,则1)proto-2发送者在消息中放置0,或者2) proto-2发送者将值设置为9999(默认值),因此不发送该值,并且proto-3接收器将其解释为0.不知道消息中是否存在该值,我的代码无法消除歧义,即使它知道消息是来自proto-2还是proto-3发送者。
请注意,示例中的bmsPos字段没有问题,因为proto-2消息使用与proto-3(0)相同的默认值。但如果您碰巧选择了与proto-3不同的默认值,那么我就不会看到如何升级到proto-3并向后兼容。
答案 0 :(得分:39)
原来有一种方法可以确定默认值是否实际丢失(感谢Google的一些朋友提供此答案):
message Record {
uint32 fileno = 1;
uint64 pos = 2;
uint64 bmsPos = 3;
oneof scanMode_present {
uint32 scanMode = 4;
}
uint32 version = 5; // set to >= 3 for protobuf 3
}
生成代码还有其他方法可以使用 getXXXcase()方法检测是否设置了 oneof 字段:
int scanMode = proto.getScanMode();
boolean isMissing = proto.getScanModePresentCase() == Record.ScanModePresentCase.SCANMODEPRESENT_NOT_SET;
if (isMissing) {
boolean isProto3 = proto.getVersion() >= 3;
scanMode = (isProto3) ? 0 : 9999;
}
通过这个'技巧,我已经升级到proto-3,向后兼容非标准proto-2默认值。