将protobuf从版本2升级到3 - 与protobuf默认值

时间:2015-10-18 23:17:13

标签: protocol-buffers

我试图升级到使用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并向后兼容。

1 个答案:

答案 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;
}
  • 请注意, oneof 的名称是任意的,我采用了惯例 fieldname_present
  • oneof 不会为有线格式添加任何内容,因此它与proto-2消息保持兼容。
  • 您可以在任何有意义的地方添加版本信息,我将其放在此示例的“记录”消息中。

通过这个'技巧,我已经升级到proto-3,向后兼容非标准proto-2默认值。