使用protobuf3踩过的那些坑(Java)

相对于 protobuf2,protobuf3 变化很大,尤其是默认值的变化给使用者带来很大不便。

默认值

protobuf3 删除了 protobuf2 中用来设置默认值的 default 关键字,取而代之的是protobuf3为各类型定义的默认值,也就是约定的默认值,如下表所示:

类型 默认值
bool false
整型 0
string 空字符串""
枚举enum 第一个枚举元素的值,因为Protobuf3强制要求第一个枚举元素的值必须是0,所以枚举的默认值就是0;
message 不是null,而是DEFAULT_INSTANCE

可以看出来,protobuf3定义的默认值跟Java中类的属性的默认值规则并不一样:Java中,如果类的属性类型是类,则该属性默认值是null,而protobuf3中,string、message的默认值都不是null。

枚举enum类型:

1、不支持一个proto文件中,多个枚举中定义相同的枚举常量名。

如下的两个枚举,定义在同一个proto文件中:

enum Enum1 {
    IDLE = 0;
    RUNNING = 1;
}

enum Enum2 {
    IDLE = 5;
    RUNNING = 6;
}

编译时,会报出错误:IDLE is already defined in "xxx",出现这一错误的原因就是:Protobuf3中不允许同一proto中,多个枚举中使用相同的枚举值。
而有意思的是:在proto编译生成的Java文件中,protobuf自己却为每个枚举都添加了一个UNRECOGNIZED(值为-1),意味着protobuf不允许使用者为两个枚举添加相同的枚举值,却允许自己添加。。。
实际上,这一现象是有悖于Java开发者习惯的,因为在Java中,并不会对枚举有上述限制,在使用上会让人感觉很别扭,带着这个困惑,我提了个bug:
Can not define two same enum name in the same proto file

而官方的解答是:
1、设计如此,给名字一样的枚举值加个前缀来解决这个问题。。。
2、Protobuf要兼顾所有语言的特性,我试了一下:C语言也不不允许这么定义(以前真不知道这个情况,学艺不精呀。。)。

2、枚举第一个常量的值必须是0

实际项目中使用的枚举常量值经常是从0开始的,这样项目需求与protobuf3有冲突。
解决方法是,将第一个枚举常量0定义为无效值,或者额外定义一个无效值(比如-1),Google API Guider中建议枚举的第一个值为 ENUN_TYPE_UNSPECIFIED,即枚举名_UNSPECIFIED,举个例子:

enum BallTypeEnum {
    BALL_TYPE_UNSPECIFIED = 0;
    BASKETBALL = 1;
    FOOTBALL = 2;
}

这样,让默认的枚举值与业务的相分离。

message类型:

Java中,message类型的默认值是DEFAULT_INSTANCE,其值相当于空的message,即XXX.newBuilder().build(),这样对message类型的判空操作就应该是这样:

// protobuf message
message User {
    int32 id = 1;
    string name = 2;
    string email = 3;
    Address address = 4;
}

message Address {
    string street = 1;
    string building = 2;
}

// Java
if (user.getAddress() != null && user.getAddress() != UserProto.Address.getDefaultInstance()) {
    ...
} else {
    ...
}

结语

尽管protobuf3有一些不方便的地方,但protobuf毕竟数据交换协议,负责交换数据,所以建议在使用protobuf时,不要与具体业务耦合过紧,protobuf相关操作放在数据传输的接口层。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,886评论 18 139
  • 由于工程项目中拟采用一种简便高效的数据交换格式,百度了一下发现除了采用 xml、JSON 还有 ProtoBuf(...
    黄海佳阅读 48,845评论 1 23
  • 翻译查阅外网资料过程中遇到的比较优秀的文章和资料,一是作为技术参考以便日后查阅,二是训练英文能力。此文翻译自 Pr...
    401阅读 68,428评论 1 39
  • 针对该款stm32芯片(stm32f107vct6)没有软件仿真库的问题,设计了新的调试方式,即通过串口打印文件名...
    Westring阅读 4,263评论 0 1
  • 1.我为什么要努力?因为我不想在一年之后所有的同学聚会的时候,仰望着谁的脸色,奉承别人的微笑;我不想在街上看到自己...
    sunshine_小丸子阅读 292评论 4 5