【问题标题】:Upgrading protobuf from version 2 to 3 - incompatible with protobuf default values将 protobuf 从版本 2 升级到 3 - 与 protobuf 默认值不兼容
【发布时间】:2015-10-18 23:17:12
【问题描述】:

我正在尝试升级到使用 protobuf 版本 3,并保持与版本 2 的向后兼容。除了一件事之外似乎可以工作 - 在 proto-2 中您可以设置自己的默认值,但在 proto 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 并向后兼容。

【问题讨论】:

    标签: protocol-buffers


    【解决方案1】:

    原来有一种方法可以查明是否确实缺少默认值(感谢 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 
    }
    

    生成代码具有额外的方法来检测是否设置了 oneof 字段,使用 getXXXcase() 方法:

    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 消息保持兼容。
    • 您可以在任何有意义的地方添加 version 信息,我将它放在此示例的 Record 消息中。

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

    【讨论】:

    • 好招!我是proto2(但不是proto3)的作者,我设计了“oneof”功能,但我不确定我是否会想到这个!
    • 不知道是谁发明的。谷歌的一位朋友帮我找到了它。认为其他人会需要它。
    • @JohnCaron,我一直在寻找相同的方法,如果我正确理解您的解决方案,它可以工作,但我有点害怕必须向所有客户端添加设置默认值的逻辑。
    • 所以基本上 oneof 是真正可选字段的 proto3 版本(例如,它可以不设置)并且可以检测它是否设置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-23
    • 1970-01-01
    相关资源
    最近更新 更多