6.JSON映射
Proto3支持JSON的编码规范,
使它更容易在不同系统之间共享数据,
在下表中按类型逐个描述对应编码。
如果json编码的数据中缺少一个值,
或者它的值为null,
这个数据在protocol buffer解析时,
会被表示成适当的默认值。
如果一个字段在protocol buffer中有默认值,
那么默认情况下它将在Json编码的数据中被省略,
以节省空间。
具体实现可以提供在JSON编码中提供选项,
输出具有默认值的字段。
proto3 | JSON | JSON example | Notes |
---|---|---|---|
message | object | {"fooBar": v, "g": null, …} |
生成JSON对象。消息字段名称映射为小驼峰,并成为JSON对象的key。如果指定了’json_name字段选项,则指定的值将被用作key。解析器同时接受小驼峰名称(或json_name选项指定的名称)和原始的原型字段名称。”null”是所有字段类型的可接受的值,并被作为对应字段类型的默认值。 |
enum | string | "FOO_BAR" |
使用proto中指定的枚举值的名称。解析器同时接受枚举名和整数值。 |
map<K,V> | object | {"k": v, …} |
所有的key都被转换成string。 |
repeated V | array | [v, …] |
null被视为空列表[]。 |
bool | true, false | true, false |
|
string | string | "Hello World!" |
|
bytes | base64 string | "YWJjMTIzIT8kKiYoKSctPUB+" |
JSON值是字符串编码的数据,使用带填充的标准base64编码。标准的或URL安全的base64编码,有没有填充都可以接受。 |
int32, fixed32, uint32 | number | 1, -10, 0 |
JSON值是一个十进制数。可以接受数字或字符串。 |
int64, fixed64, uint64 | string | "1", "-10" |
JSON值将是一个十进制字符串。可以接受数字或字符串。 |
float, double | number | 1.1, -10.0, 0, "NaN", "Infinity" |
JSON值是一个数字或特殊字符串值“NaN”、“Infinity”和“-Infinity”中的一个。可以接受数字或字符串。指数符号也被接受。-0被认为等于0。 |
Any | object |
{"@type": "url", "f": v, … } |
如果一个Any有一个特别的JSON映射,则它会转换成如下形式:{"@type": xxx, "value": yyy} 。否则,该值会被转换成一个JSON对象,@type 字段将被插入,以指示实际的数据类型。 |
Timestamp | string | "1972-01-01T10:00:20.021Z" |
使用RFC 3339,其中生成的输出将始终是Z标准化的,并使用0、3、6或9位小数。也接受除Z以外的偏移量。 |
Duration | string | "1.000340012s", "1s" |
生成的输出总是包含0、3、6或9个小数(取决于所需的精度),后面跟着后缀s。任何小数都可以接受,只要它们能满足纳米秒的精确度,并且需要后缀s。 |
Struct | object |
{ … } |
任意的JSON对象,参见struct.proto。 |
Wrapper types | various types | 2, "2", "foo", true, "true", null, 0, … |
包装器在JSON中的表示方式类似于原始类型,但是nulll在数据转换和传输期间被允许和保留。 |
FieldMask | string | "f.fooBar,h" |
参见field_mask.proto . |
ListValue | array | [foo, bar, …] |
|
Value | value | 任意JSON值,细节请参见 google.protobuf.Value。 | |
NullValue | null | JSON null | |
Empty | object | {} | 空JSON对象 |
6.1.JSON选项
proto3的JSON实现可以提供以下选项:
- 带有默认值的字段:带有默认值的字段在proto3的JSON输出中默认被省略。有一个选项,可以覆盖此行为,输出字段可以携带默认值。
- 忽略未知字段:默认情况下,proto3的JSON解析器应该拒绝未知字段,但是可以在解析中提供忽略未知字段的选项。
- 使用原型字段名称而不是小驼峰名称:默认情况下,proto3的 JSON打印器应该将字段名称转换为小驼峰,并使用它作为JSON名称。有一个使用原型字段名称作为JSON名称的选项。proto3的 JSON解析器需要同时接受转换后的小驼峰名称和原型字段名。
- 枚举值以整数而不是字符串的形式输出:在JSON输出中默认使用枚举值的名称。有一个选项,可以使用枚举值的数值来代替。
7.选项
proto文件中的单个声明可以用许多选项进行注释。
选项不会改变声明的总体含义,
但可能会影响在特定环境下处理声明的方式。
可用选项的完整列表在google/protobuf/descriptor.proto中。
一些选项是文件级别的,
这意味着它们应该在顶级作用域中编写,
而不是在任何消息、枚举或服务定义中。
有些选项是消息级选项,
这意味着它们应该写入消息定义中。
有些选项是字段级选项,
这意味着它们应该写入字段定义中。
选项也可以写入枚举类型、枚举值、字段、服务类型和服务方法;
但是到目前为止,
并没有一种选项能作用于所有的类型。
- java_package(文件选项):这个选项用于指定生成java类所在的包。如果在.proto文件中没有显示的声明java_package,就采用默认的包名。默认情况下将使用proto包(在.proto文件中使用package关键字指定)。然而默认包通常不能成为好的Java包,因为它不是以反向域名开始。如果不生成Java代码,则此选项无效。例如:
option java_package = "com.example.foo";
- java_multiple_files(文件选项):是否生成多个Java文件,true定义的所有消息、枚举和服务生成对应的多个类文件,false只有一个文件,所有对象以内部类的形式出现。例如:
option java_multiple_files = true;
- java_outer_classname(文件选项):这个选项指定要生成Java类的名称。如果在.proto文件中没有明确指定java_outer_classname,生成的class名称将会根据.proto文件的名称采用驼峰命名。比如foo_bar.proto生成的java类名为FooBar.java,如果不生成java代码,则该选项不起任何作用。例如:
option java_outer_classname = "Ponycopter";
- optimize_for(文件选项):可以设置为SPEED、CODE_SIZE或LITE_RUNTIME。这些值将通过如下方式对c++和Java代码生成器(可能还有第三方生成器)产生以下影响:
- SPEED(默认值):protocol buffer将生成用于序列化、解析和对消息类型执行其他常见操作的代码。这段代码经过了高度优化。
- CODE_SIZE:protocol buffer编译器将会生成最少的类,通过共享或基于反射的代码来实现序列化、解析和各种其他操作。因此生成的代码将比SPEED要小得多, 但操作将更慢。当然实现的类及其对外的API与SPEED模式都是一样的。这种模式在包含大量.proto文件的应用程序中非常有用,而且不需要把所有文件都快速保存下来。
- LITE_RUNTIME:protocol buffer编译器将生成只依赖于lite运行时库(libprotobuf-lite,而不是libprotobuf)的类。lite运行时比整个库小得多(大约小一个数量级),但是省略了某些特性,比如描述符和反射。这对于运行在受限平台(如手机)上的应用程序尤其有用。编译器仍然会像在SPEED模式下那样生成所有方法的快速实现。生成的类将只以每种语言实现MessageLite接口,它只提供完整消息接口方法的一个子集。
option optimize_for = CODE_SIZE;
- cc_enable_arenas(文件选项):为C++生成的代码启用arena分配。
- objc_class_prefix(文件选项):设置Objective-C类的前缀,该前缀被前置到所有Objective-C生成的类和枚举中。没有默认值。按照苹果公司的建议,应该使用3-5个大写字母之间的前缀。注意,所有两个字母的前缀都是苹果保留的。
- deprecated(字段选项):如果设置为true则表示该字段已经被废弃,并且不应该在新的代码中使用。在大多数语言中没有实际的效果。在Java中,这会变成@Deprecated注解,将来其他语言的代码生成器也许会在字标识符中产生废弃注解,废弃注解会在编译器尝试使用该字段时发出警告。如果字段没有被使用,也不希望新用户使用它,可以考虑使用保留语句替换该字段声明。
int32 old_field = 6 [deprecated = true];
7.1.自定义选项
Protocol Buffers允许定义和使用自己的选项。这是一个大多数人不需要的高级特性。如果您确实认为需要创建自己的选项,请参阅Proto2语言指南了解详细信息。注意创建自定义选项使用扩展,这只允许在proto3中自定义选项。
8.生成代码类
要生成Java、Python、C++、Go、Ruby、Objective-C或C#代码,
可以通过在.proto文件中定义消息、枚举、服务等,
需要在.proto上运行protocol buffer编译器protoc。
如果还没有安装编译器,
请下载安装包并按照README中的说明操作。
对于Go,还需要为编译器安装一个特殊的代码生成器插件:
可以在GitHub上的golang/protobuf存储库中找到这个插件和安装说明。
protocol buffer调用方式如下:
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --javanano_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto
-
IMPORT_PATH指定了一个目录,当解析import路径时在其中查找.proto文件。如果省略该值,则使用当前目录。可以通过多次传递–proto_path选项来指定多个导入目录;它们会被按照顺序搜索。-I=IMPORT_PATH是–proto_path的简化形式。
- –ccpp_out在DST_DIR中生成C++代码。更多信息请参见C++生成的代码参考。
- –cjava_out在DST_DIR中生成Java代码。更多信息请参见Java生成的代码参考。
- –cpython_out在DST_DIR中生成Python代码。有关更多信息,请参阅Python生成的代码参考。
- –cgo_out在DST_DIR中生成Go代码。更多信息请参见Go生成的代码参考。
- –cruby_out在DST_DIR中生成Ruby代码。Ruby生成的代码参考即将发布!
- –cobjc_out在DST_DIR中生成Objective-C代码。更多信息请参见Objective-C生成的代码参考。
- –ccsharp_out在DST_DIR中生成C#代码。更多信息请参见C#生成的代码参考。
- –cphp_out在DST_DIR中生成PHP代码。有关更多信息,请参阅PHP生成的代码参考。另外一个方便的地方是,如果DST_DIR以.zip或. JAR结尾,编译器将输出写入具有给定名称的单个zip格式存档文件,.JAR输出还将根据Java JAR规范提供一个清单文件。注意,如果输出存档已经存在,它将被覆盖;编译器不够聪明,无法向现有的归档文件中添加文件。
-
必须提供一个或多个.proto文件作为输入。可以同时指定多个.proto文件。尽管文件的命名是相对于当前目录的,每个文件必须位于其IMPORT_PATH下,这样编译器才能确定它的规范名称。
9.参考文章
Language Guide (proto3)
Protobuf3教程
ProtoBuf v3 语法简介
gRPC之proto语法