encoding/jsonpb: fix encoding of empty google.protobuf.Value
Description of message Value states:
`Value` represents a dynamically typed value which can be either null, a
number, a string, a boolean, a recursive struct value, or a list of values. A
producer of value is expected to set one of that variants, absence of any
variant indicates an error.
https://github.com/protocolbuffers/protobuf/blob/3.7.x/src/google/protobuf/struct.proto#L57-L60
Previous implementation was following C++ lib behavior.
Change-Id: Id51792e2fc8cc465a05a978e63410d3b6802b522
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/168901
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/jsonpb/encode.go b/encoding/jsonpb/encode.go
index a9ca581..9bfadda 100644
--- a/encoding/jsonpb/encode.go
+++ b/encoding/jsonpb/encode.go
@@ -111,14 +111,8 @@
continue
}
- // An empty google.protobuf.Value should NOT be marshaled out.
- // Hence need to check ahead for this.
- val := knownFields.Get(num)
- if isEmptyKnownValue(val, fd.MessageType()) {
- continue
- }
-
name := fd.JSONName()
+ val := knownFields.Get(num)
if err := e.WriteName(name); !nerr.Merge(err) {
return err
}
diff --git a/encoding/jsonpb/encode_test.go b/encoding/jsonpb/encode_test.go
index 74dd570..d6a2e62 100644
--- a/encoding/jsonpb/encode_test.go
+++ b/encoding/jsonpb/encode_test.go
@@ -1008,15 +1008,15 @@
input: &knownpb.Empty{},
want: `{}`,
}, {
- desc: "Value empty",
- input: &knownpb.Value{},
- want: ``,
+ desc: "Value empty",
+ input: &knownpb.Value{},
+ wantErr: true,
}, {
desc: "Value empty field",
input: &pb2.KnownTypes{
OptValue: &knownpb.Value{},
},
- want: `{}`,
+ wantErr: true,
}, {
desc: "Value contains NullValue",
input: &knownpb.Value{Kind: &knownpb.Value_NullValue{}},
@@ -1531,7 +1531,7 @@
},
input: func() proto.Message {
m := &knownpb.Value{}
- b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
+ b, err := proto.Marshal(m)
if err != nil {
t.Fatalf("error in binary marshaling message for Any.value: %v", err)
}
@@ -1540,9 +1540,7 @@
Value: b,
}
}(),
- want: `{
- "@type": "type.googleapis.com/google.protobuf.Value"
-}`,
+ wantErr: true,
}, {
desc: "Any with Duration",
mo: jsonpb.MarshalOptions{
@@ -1641,7 +1639,9 @@
{Kind: &knownpb.Value_ListValue{}},
},
},
- OptValue: &knownpb.Value{},
+ OptValue: &knownpb.Value{
+ Kind: &knownpb.Value_StringValue{"world"},
+ },
OptEmpty: &knownpb.Empty{},
OptAny: &knownpb.Any{
TypeUrl: "google.protobuf.Empty",
@@ -1671,6 +1671,7 @@
{},
[]
],
+ "optValue": "world",
"optEmpty": {},
"optAny": {
"@type": "google.protobuf.Empty"
diff --git a/encoding/jsonpb/well_known_types.go b/encoding/jsonpb/well_known_types.go
index a9efdd3..101e4ba 100644
--- a/encoding/jsonpb/well_known_types.go
+++ b/encoding/jsonpb/well_known_types.go
@@ -128,10 +128,6 @@
// with corresponding custom JSON encoding of the embedded message as a
// field.
if isCustomType(emt.FullName()) {
- // An empty google.protobuf.Value should NOT be marshaled out.
- if isEmptyKnownValue(pref.ValueOf(em), emt) {
- return nil
- }
e.WriteName("value")
return e.marshalCustomType(em)
}
@@ -176,14 +172,6 @@
return e.marshalList(val.List(), fd)
}
-// isEmptyKnownValue returns true if given val is of type google.protobuf.Value
-// and does not have any of its oneof fields set.
-func isEmptyKnownValue(val pref.Value, md pref.MessageDescriptor) bool {
- return md != nil &&
- md.FullName() == "google.protobuf.Value" &&
- val.Message().KnownFields().Len() == 0
-}
-
func (e encoder) marshalKnownValue(m pref.Message) error {
msgType := m.Type()
fieldDescs := msgType.Oneofs().Get(0).Fields()
@@ -200,8 +188,8 @@
return e.marshalSingular(val, fd)
}
- // None of the fields are set.
- return nil
+ // Return error if none of the fields are set.
+ return errors.New("%s: none of the variants is set", msgType.FullName())
}
const (