encoding/protojson: add MarshalOptions.UseEnumNumbers
UseEnumNumbers=true will emit enum values as JSON numbers.
Change-Id: I6f3c814e06dc1e3dd595ad35aa79871a49718cd5
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/194017
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/protojson/encode.go b/encoding/protojson/encode.go
index c761fec..d55786e 100644
--- a/encoding/protojson/encode.go
+++ b/encoding/protojson/encode.go
@@ -34,6 +34,9 @@
// Marshal will return error if there are any missing required fields.
AllowPartial 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:
@@ -197,14 +200,16 @@
case pref.EnumKind:
if fd.Enum().FullName() == "google.protobuf.NullValue" {
o.encoder.WriteNull()
- } else if desc := fd.Enum().Values().ByNumber(val.Enum()); desc != nil {
- err := o.encoder.WriteString(string(desc.Name()))
- if err != nil {
- return err
- }
} else {
- // Use numeric value if there is no enum value descriptor.
- o.encoder.WriteInt(int64(val.Enum()))
+ desc := fd.Enum().Values().ByNumber(val.Enum())
+ if o.UseEnumNumbers || desc == nil {
+ o.encoder.WriteInt(int64(val.Enum()))
+ } else {
+ err := o.encoder.WriteString(string(desc.Name()))
+ if err != nil {
+ return err
+ }
+ }
}
case pref.MessageKind, pref.GroupKind:
diff --git a/encoding/protojson/encode_test.go b/encoding/protojson/encode_test.go
index 661ee59..4ee275a 100644
--- a/encoding/protojson/encode_test.go
+++ b/encoding/protojson/encode_test.go
@@ -2125,6 +2125,56 @@
}
]
}`,
+ }, {
+ desc: "UseEnumNumbers in singular field",
+ mo: protojson.MarshalOptions{UseEnumNumbers: true},
+ input: &pb2.Enums{
+ OptEnum: pb2.Enum_ONE.Enum(),
+ OptNestedEnum: pb2.Enums_UNO.Enum(),
+ },
+ want: `{
+ "optEnum": 1,
+ "optNestedEnum": 1
+}`,
+ }, {
+ desc: "UseEnumNumbers in repeated field",
+ mo: protojson.MarshalOptions{UseEnumNumbers: true},
+ input: &pb2.Enums{
+ RptEnum: []pb2.Enum{pb2.Enum_ONE, 2, pb2.Enum_TEN, 42},
+ RptNestedEnum: []pb2.Enums_NestedEnum{pb2.Enums_UNO, pb2.Enums_DOS, 47},
+ },
+ want: `{
+ "rptEnum": [
+ 1,
+ 2,
+ 10,
+ 42
+ ],
+ "rptNestedEnum": [
+ 1,
+ 2,
+ 47
+ ]
+}`,
+ }, {
+ desc: "UseEnumNumbers in map field",
+ mo: protojson.MarshalOptions{UseEnumNumbers: true},
+ input: &pb3.Maps{
+ Uint64ToEnum: map[uint64]pb3.Enum{
+ 1: pb3.Enum_ONE,
+ 2: pb3.Enum_TWO,
+ 10: pb3.Enum_TEN,
+ 47: 47,
+ },
+ },
+ want: `{
+ "uint64ToEnum": {
+ "1": 1,
+ "2": 2,
+ "10": 10,
+ "47": 47
+ }
+}`,
}}
for _, tt := range tests {