diff --git a/runtime/marshal_jsonpb.go b/runtime/marshal_jsonpb.go index 2fbb2628727..f0de351b212 100644 --- a/runtime/marshal_jsonpb.go +++ b/runtime/marshal_jsonpb.go @@ -172,7 +172,7 @@ func decodeJSONPb(d *json.Decoder, v interface{}) error { if !ok { return decodeNonProtoField(d, v) } - unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true} + unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields} return unmarshaler.UnmarshalNext(d, p) } @@ -186,7 +186,7 @@ func decodeNonProtoField(d *json.Decoder, v interface{}) error { rv.Set(reflect.New(rv.Type().Elem())) } if rv.Type().ConvertibleTo(typeProtoMessage) { - unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: true} + unmarshaler := &jsonpb.Unmarshaler{AllowUnknownFields: allowUnknownFields} return unmarshaler.UnmarshalNext(d, rv.Interface().(proto.Message)) } rv = rv.Elem() @@ -248,3 +248,15 @@ var typeProtoMessage = reflect.TypeOf((*proto.Message)(nil)).Elem() func (j *JSONPb) Delimiter() []byte { return []byte("\n") } + +// allowUnknownFields helps not to return an error when the destination +// is a struct and the input contains object keys which do not match any +// non-ignored, exported fields in the destination. +var allowUnknownFields = true + +// DisallowUnknownFields enables option in decoder (unmarshaller) to +// return an error when it finds an unknown field. This function must be +// called before using the JSON marshaller. +func DisallowUnknownFields() { + allowUnknownFields = false +} diff --git a/runtime/marshal_jsonpb_test.go b/runtime/marshal_jsonpb_test.go index 00590e94401..7d60ef7ce35 100644 --- a/runtime/marshal_jsonpb_test.go +++ b/runtime/marshal_jsonpb_test.go @@ -468,6 +468,25 @@ func TestJSONPbDecoderFields(t *testing.T) { } } +func TestJSONPbDecoderUnknownField(t *testing.T) { + var ( + m runtime.JSONPb + got examplepb.ABitOfEverything + ) + data := `{ + "uuid": "6EC2446F-7E89-4127-B3E6-5C05E6BECBA7", + "unknownField": "111" + }` + + runtime.DisallowUnknownFields() + + r := strings.NewReader(data) + dec := m.NewDecoder(r) + if err := dec.Decode(&got); err == nil { + t.Errorf("m.Unmarshal(&got) not failed; want `unknown field` error; data=%q", data) + } +} + var ( fieldFixtures = []struct { data interface{}