当前位置: 首页 > 知识库问答 >
问题:

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

鲜于意
2023-03-14

我正在尝试升级到使用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-3api没有告诉您消息中是否有默认值,它只是告诉您值。

所以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个答案

史飞尘
2023-03-14

事实证明,有一种方法可以确定默认值是否确实丢失(感谢谷歌的一些朋友的回答):

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 
}

generate代码使用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;
}
  • 请注意,其中一个的名称是任意的,我采用了约定fieldname\u present

有了这个“技巧”,我升级到了proto-3,向后兼容非标准proto-2默认值。

 类似资料:
  • 我目前在tensorflow中使用RNN时遇到了这个错误: 这个程序需要协议缓冲区运行库的3.3.0版本,但是安装的版本是2.6.1。请更新您的库。如果您自己编译程序,请确保您的标头来自与链接时库相同的协议缓冲区版本。(版本验证失败在"bazel-out/local_linux-opt/genfile/tenorflow/contrib/tensor_forest/proto/fertile_st

  • 我们最近收到一封来自AWS的邮件: 主题:[需要的操作]关于简单电子邮件服务的重要通知(SIGv2弃用) 正文:我们最近观察到来自您帐户的Amazon SES SMTPendpoint上的签名版本2请求 问题: 我们没有使用AWS SES API发送请求,我们只是使用SmtpClient发送电子邮件。此方法不提供签名请求。他们自己的例子不包括任何签名。https://docs.aws.amazon

  • 如果您打算升级一个早先版本的 Jekyll,那么一些发生在 1.0 及 2.0 版本中的相关变化,您需要首先了解下。 在我们开始动手之前,请先获取最新版本的 Jekyll: $ gem update jekyll 立即开始 想快速构建并运行一个全新的 Jekyll 站点吗?那么只要执行 jekyll new SITENAME 即可!该命令会创建一个包含了 Jekyll 最基础框架的文件夹。 Jek

  • 2.7.x升级步骤及注意事项

  • 请阅读相应的升级注意事项。 从 2.2.5 升级到 2.2.6 从 2.2.4 升级到 2.2.5 从 2.2.3 升级到 2.2.4 从 2.2.2 升级到 2.2.3 从 2.2.1 升级到 2.2.2 从 2.2.0 升级到 2.2.1 从 2.1.4 升级到 2.2.0 从 2.1.3 升级到 2.1.4 从 2.1.2 升级到 2.1.3 从 2.1.1 升级到 2.1.2 从 2.1.

  • 请根据你要升级的版本阅读相应的升级注意事项。