encoding/jsonpb: update handling of Empty message type

The "custom" JSON representation for Empty is {}. And hence, when
embedded in Any, it needs to be represented as a field value in the
"value" field.

Discussion at https://github.com/protocolbuffers/protobuf/issues/5390.

As of this CL, code currently handles marshaling of Empty embedded
in Any, but not unmarshaling of Any yet. I'd like to get this corrected
first in order to proceed with unmarshaling of Any.

Change-Id: Ic0c321be188a979909b99d6b467aabc57c48e95c
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/169702
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
Herbie Ong 2019-03-27 15:21:43 -07:00
parent 329be5b5fc
commit 82014a51c5
2 changed files with 37 additions and 4 deletions

View File

@ -1631,8 +1631,6 @@ func TestMarshal(t *testing.T) {
"value": true
}`,
}, {
// TODO: Need clarification on the specification for this. See
// https://github.com/protocolbuffers/protobuf/issues/5390
desc: "Any with Empty",
mo: jsonpb.MarshalOptions{
Resolver: preg.NewTypes((&knownpb.Empty{}).ProtoReflect().Type()),
@ -1649,7 +1647,8 @@ func TestMarshal(t *testing.T) {
}
}(),
want: `{
"@type": "type.googleapis.com/google.protobuf.Empty"
"@type": "type.googleapis.com/google.protobuf.Empty",
"value": {}
}`,
}, {
desc: "Any with StringValue containing invalid UTF8",
@ -1843,7 +1842,8 @@ func TestMarshal(t *testing.T) {
"optValue": "world",
"optEmpty": {},
"optAny": {
"@type": "google.protobuf.Empty"
"@type": "google.protobuf.Empty",
"value": {}
},
"optFieldmask": "fooBar,barFoo"
}`,

View File

@ -34,6 +34,7 @@ func isCustomType(name pref.FullName) bool {
"google.protobuf.UInt64Value",
"google.protobuf.StringValue",
"google.protobuf.BytesValue",
"google.protobuf.Empty",
"google.protobuf.Struct",
"google.protobuf.ListValue",
"google.protobuf.Value",
@ -65,6 +66,9 @@ func (o MarshalOptions) marshalCustomType(m pref.Message) error {
"google.protobuf.BytesValue":
return o.marshalWrapperType(m)
case "google.protobuf.Empty":
return o.marshalEmpty(m)
case "google.protobuf.Struct":
return o.marshalStruct(m)
@ -107,6 +111,9 @@ func (o UnmarshalOptions) unmarshalCustomType(m pref.Message) error {
"google.protobuf.BytesValue":
return o.unmarshalWrapperType(m)
case "google.protobuf.Empty":
return o.unmarshalEmpty(m)
case "google.protobuf.Struct":
return o.unmarshalStruct(m)
@ -224,6 +231,32 @@ func (o UnmarshalOptions) unmarshalWrapperType(m pref.Message) error {
return nerr.E
}
// The JSON representation for Empty is an empty JSON object.
func (o MarshalOptions) marshalEmpty(pref.Message) error {
o.encoder.StartObject()
o.encoder.EndObject()
return nil
}
func (o UnmarshalOptions) unmarshalEmpty(pref.Message) error {
jval, err := o.decoder.Read()
if err != nil {
return err
}
if jval.Type() != json.StartObject {
return unexpectedJSONError{jval}
}
jval, err = o.decoder.Read()
if err != nil {
return err
}
if jval.Type() != json.EndObject {
return unexpectedJSONError{jval}
}
return nil
}
// The JSON representation for Struct is a JSON object that contains the encoded
// Struct.fields map and follows the serialization rules for a map.