encoding/protojson: add MarshalOptions.UseProtoNames
UseProtoNames=true uses proto field name in JSON field names.
Change-Id: I23249dc1787d9735bef780b1ef8d294a9c55c043
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/193998
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/protojson/encode.go b/encoding/protojson/encode.go
index d55786e..1662e40 100644
--- a/encoding/protojson/encode.go
+++ b/encoding/protojson/encode.go
@@ -34,23 +34,27 @@
// Marshal will return error if there are any missing required fields.
AllowPartial bool
+ // UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
+ // field names.
+ UseProtoNames bool
+
// UseEnumNumbers emits enum values as numbers.
UseEnumNumbers bool
// EmitUnpopulated specifies whether to emit unpopulated fields. It does not
// emit unpopulated oneof fields or unpopulated extension fields.
// The JSON value emitted for unpopulated fields are as follows:
- // ╔═══════╤════════════════════════════╗
- // ║ JSON │ Protobuf field ║
- // ╠═══════╪════════════════════════════╣
- // ║ false │ proto3 boolean fields ║
- // ║ 0 │ proto3 numeric fields ║
- // ║ "" │ proto3 string/bytes fields ║
- // ║ null │ proto2 scalar fields ║
- // ║ null │ message fields ║
- // ║ [] │ list fields ║
- // ║ {} │ map fields ║
- // ╚═══════╧════════════════════════════╝
+ // ╔═══════╤════════════════════════════╗
+ // ║ JSON │ Protobuf field ║
+ // ╠═══════╪════════════════════════════╣
+ // ║ false │ proto3 boolean fields ║
+ // ║ 0 │ proto3 numeric fields ║
+ // ║ "" │ proto3 string/bytes fields ║
+ // ║ null │ proto2 scalar fields ║
+ // ║ null │ message fields ║
+ // ║ [] │ list fields ║
+ // ║ {} │ map fields ║
+ // ╚═══════╧════════════════════════════╝
EmitUnpopulated bool
// If Indent is a non-empty string, it causes entries for an Array or Object
@@ -128,6 +132,13 @@
}
name := fd.JSONName()
+ if o.UseProtoNames {
+ name = string(fd.Name())
+ // Use type name for group field name.
+ if fd.Kind() == pref.GroupKind {
+ name = string(fd.Message().Name())
+ }
+ }
if err := o.encoder.WriteName(name); err != nil {
return err
}
diff --git a/encoding/protojson/encode_test.go b/encoding/protojson/encode_test.go
index 4ee275a..9a1c86e 100644
--- a/encoding/protojson/encode_test.go
+++ b/encoding/protojson/encode_test.go
@@ -2175,6 +2175,46 @@
"47": 47
}
}`,
+ }, {
+ desc: "UseProtoNames",
+ mo: protojson.MarshalOptions{UseProtoNames: true},
+ input: &pb2.Nests{
+ OptNested: &pb2.Nested{},
+ Optgroup: &pb2.Nests_OptGroup{
+ OptString: proto.String("inside a group"),
+ OptNested: &pb2.Nested{
+ OptString: proto.String("nested message inside a group"),
+ },
+ Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
+ OptFixed32: proto.Uint32(47),
+ },
+ },
+ Rptgroup: []*pb2.Nests_RptGroup{
+ {
+ RptString: []string{"hello", "world"},
+ },
+ },
+ },
+ want: `{
+ "opt_nested": {},
+ "OptGroup": {
+ "opt_string": "inside a group",
+ "opt_nested": {
+ "opt_string": "nested message inside a group"
+ },
+ "OptNestedGroup": {
+ "opt_fixed32": 47
+ }
+ },
+ "RptGroup": [
+ {
+ "rpt_string": [
+ "hello",
+ "world"
+ ]
+ }
+ ]
+}`,
}}
for _, tt := range tests {