Skip to content

Commit

Permalink
jsonpb: bring back old behaviour of handling nulls and JSONPBUnmarshaler
Browse files Browse the repository at this point in the history
Change how jsonpb.Unmarshal handles nested JSONPBMarshaler fields a null json values.

When json null is encountered for a field which implements JSONPBUnmarshaler, jsonpb will now calli unmarshal method from the field, instead of just assigning nil to this field.
  • Loading branch information
krzysztofdrys committed Mar 22, 2021
1 parent a36a1a1 commit 2ab1774
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 7 deletions.
27 changes: 21 additions & 6 deletions jsonpb/decode.go
Expand Up @@ -135,14 +135,14 @@ func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error
md := m.Descriptor()
fds := md.Fields()

if string(in) == "null" && md.FullName() != "google.protobuf.Value" {
return nil
}

if jsu, ok := proto.MessageV1(m.Interface()).(JSONPBUnmarshaler); ok {
return jsu.UnmarshalJSONPB(u, in)
}

if string(in) == "null" && md.FullName() != "google.protobuf.Value" {
return nil
}

switch wellKnownType(md.FullName()) {
case "Any":
var jsonObject map[string]json.RawMessage
Expand Down Expand Up @@ -332,11 +332,12 @@ func (u *Unmarshaler) unmarshalMessage(m protoreflect.Message, in []byte) error
raw = v
}

field := m.NewField(fd)
// Unmarshal the field value.
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd)) {
if raw == nil || (string(raw) == "null" && !isSingularWellKnownValue(fd) && !isUnmarshalJSONPB(field, fd)) {
continue
}
v, err := u.unmarshalValue(m.NewField(fd), raw, fd)
v, err := u.unmarshalValue(field, raw, fd)
if err != nil {
return err
}
Expand Down Expand Up @@ -390,6 +391,20 @@ func isSingularWellKnownValue(fd protoreflect.FieldDescriptor) bool {
return false
}

func isUnmarshalJSONPB(v protoreflect.Value, fd protoreflect.FieldDescriptor) bool {
if fd.Kind() != protoreflect.MessageKind {
return false
}
if fd.Cardinality() == protoreflect.Repeated {
return false
}

i := v.Interface()
m := proto.MessageV1(i)
_, ok := m.(JSONPBUnmarshaler)
return ok
}

func (u *Unmarshaler) unmarshalValue(v protoreflect.Value, in []byte, fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
switch {
case fd.IsList():
Expand Down
2 changes: 1 addition & 1 deletion jsonpb/json_test.go
Expand Up @@ -1009,7 +1009,7 @@ func TestUnmarshalNullWithJSONPBUnmarshaler(t *testing.T) {
t.Errorf("unmarshal error: %v", err)
}

want := ptrFieldMessage{}
want := ptrFieldMessage{StringField: &stringField{IsSet: true, StringValue: "null"}}
if !proto.Equal(&ptrFieldMsg, &want) {
t.Errorf("unmarshal result StringField: got %v, want %v", ptrFieldMsg, want)
}
Expand Down

0 comments on commit 2ab1774

Please sign in to comment.