Skip to content

Unmarshal a value which implements JSONPBUnmarshaler #429

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

Merged
merged 1 commit into from
Sep 20, 2017
Merged

Unmarshal a value which implements JSONPBUnmarshaler #429

merged 1 commit into from
Sep 20, 2017

Conversation

vaporz
Copy link
Contributor

@vaporz vaporz commented Sep 18, 2017

Hi, our test cases are failed by #394 .
We defined a struct which implements interface JSONPBUnmarshaler, and use it as a field in another message, for example:

message MyString {
  bool null = 1;
  string value = 2;
}
message Request {
  MyString name = 1;
}

MyString implements JSONPBUnmarshaler .

Before #394 , everything works fine.
After #394 , if input json is {"name": null}, func UnmarshalJSONPB on MyString is not executed. Because it will return earlier:

if string(inputValue) == "null" && targetType != reflect.TypeOf(&stpb.Value{}) {
	return nil   // <---returned here
}

@cybrcodr cybrcodr self-requested a review September 18, 2017 20:52
Copy link
Contributor

@cybrcodr cybrcodr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a unit test for this? Thanks.

jsonpb/jsonpb.go Outdated
@@ -673,7 +673,8 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
if targetType.Kind() == reflect.Ptr {
// If input value is "null" and target is a pointer type, then the field should be treated as not set
// UNLESS the target is structpb.Value, in which case it should be set to structpb.NullValue.
if string(inputValue) == "null" && targetType != reflect.TypeOf(&stpb.Value{}) {
_, ok := target.Interface().(JSONPBUnmarshaler)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor naming suggestion. s/ok/isJSONPBUnmarshaler/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

@cybrcodr
Copy link
Contributor

Curious, how do you make MyString implement JSONPBUnmarshaler? Do you hand modify the generated pb.go file or add another file under the same generated package?

@vaporz
Copy link
Contributor Author

vaporz commented Sep 19, 2017

Hi, yes, we add another file under the same generated package.

@vaporz
Copy link
Contributor Author

vaporz commented Sep 19, 2017

Hi, @cybrcodr , renamed "ok" to "isJSONPBUnmarshaler", and added a test.

Copy link
Contributor

@cybrcodr cybrcodr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Minor suggestions.

@@ -789,6 +789,18 @@ func TestUnmarshalJSONPBUnmarshaler(t *testing.T) {
if msg.rawJson != rawJson {
t.Errorf("message contents not set correctly after unmarshalling JSON: got %s, wanted %s", msg.rawJson, rawJson)
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate this out to a different Test function to make it easier to identify. Suggest naming TestUnmarshalNullWithJSONPBUnmarshaler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

rawJson = `{"stringField":null}`
var ptrFieldMsg ptrFieldMessage
if err := Unmarshal(strings.NewReader(rawJson), &ptrFieldMsg); err != nil {
t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify the error message -- "unmarshal error: %v", err

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if err := Unmarshal(strings.NewReader(rawJson), &ptrFieldMsg); err != nil {
t.Errorf("an unexpected error occurred when parsing into JSONPBUnmarshaler: %v", err)
}
if ptrFieldMsg.StringField == nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be more precise to compare with expected value. Use proto.Equal to compare.

Error message can be something like "unmarshal result StringField: got %v, want %v"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

if ptrFieldMsg.StringField == nil {
t.Errorf("ptr field which implements JSONPBUnmarshaler is nil after unmarshalling with JSON {\"stringField\":null}:")
}
if ptrFieldMsg.StringField != nil && ptrFieldMsg.StringField.IsSet == false {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if you need the IsSet field. But if you really want to keep it, the validation here should not need to include check for StringField != nil, i.e. it should be independent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this validation, "proto.Equal" is enough, but "IsSet" is not removed, I'd like to use it to make sure func (s *stringField) UnmarshalJSONPB is executed.

func (s *stringField) ProtoMessage() {
}

func (s *stringField) MarshalJSONPB(jm *Marshaler) ([]byte, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional. This is not necessary since the test is only on JSONPBUnmarshaler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, removed

Copy link
Contributor

@cybrcodr cybrcodr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@cybrcodr cybrcodr merged commit 130e6b0 into golang:master Sep 20, 2017
@golang golang locked and limited conversation to collaborators Jun 26, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants