-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jsonpb: change Marshal/Unmarshal to return error if any required field is not set #472
Changes from 1 commit
f269205
49ce6df
c24ad06
f899cde
5f2e3b1
1f41e39
a7bdcd1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -257,12 +257,17 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU | |
continue | ||
} | ||
|
||
prop := jsonProperties(valueField, m.OrigName) | ||
// IsNil will panic on most value kinds. | ||
switch value.Kind() { | ||
case reflect.Chan, reflect.Func, reflect.Interface: | ||
if value.IsNil() { | ||
continue | ||
} | ||
case reflect.Ptr: | ||
if prop.Required && value.IsNil() { | ||
return fmt.Errorf("required field %q is not set", prop.Name) | ||
} | ||
} | ||
|
||
if !m.EmitDefaults { | ||
|
@@ -300,8 +305,8 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU | |
sv := value.Elem().Elem() // interface -> *T -> T | ||
value = sv.Field(0) | ||
valueField = sv.Type().Field(0) | ||
prop = jsonProperties(valueField, m.OrigName) | ||
} | ||
prop := jsonProperties(valueField, m.OrigName) | ||
if !firstField { | ||
m.writeSep(out) | ||
} | ||
|
@@ -644,7 +649,19 @@ func (u *Unmarshaler) UnmarshalNext(dec *json.Decoder, pb proto.Message) error { | |
// permutations of the related Marshaler. | ||
func (u *Unmarshaler) Unmarshal(r io.Reader, pb proto.Message) error { | ||
dec := json.NewDecoder(r) | ||
return u.UnmarshalNext(dec, pb) | ||
if err := u.UnmarshalNext(dec, pb); err != nil { | ||
return err | ||
} | ||
|
||
// Marshal it back to check for missing required field error. | ||
// TODO: Parse through the message and check for any missing required field w/o having to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This TODO will need to be resolved before this could be considered for merging. Marshaling the JSON just after Unmarshaling is going to build in a lot of overhead that wouldn’t be a good idea to pass around. (Especially for everyone using proto3, where required fields have been entirely removed.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree that this needs to be improved. Sorry if I wasn't clear in my initial posting. I didn't intend to merge this yet. Since I didn't have time this week to continue doing this, I decided to post this PR for others to try it out and see if anyone may be interested in improving it further. Note though that a proto3 message can contain a proto2 message and vice-versa. So, as far as I know, the code will still need to traverse all the fields and subfields of the message looking for required ones that are not set. |
||
// marshal. | ||
m := &Marshaler{AnyResolver: u.AnyResolver} | ||
if _, err := m.MarshalToString(pb); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// UnmarshalNext unmarshals the next protocol buffer from a JSON object stream. | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious, for error messages like this, should I use Name or OrigName? Or is it dependent on whether message is for marshaling or unmarshaling?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Properties.Name
is fine. It's even documented as such: "name of the field, for error messages"