Skip to content
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

encoding/json: Unexpected marshal behavior #21903

Closed
alexandrevicenzi opened this issue Sep 15, 2017 · 5 comments

Comments

Projects
None yet
5 participants
@alexandrevicenzi
Copy link

commented Sep 15, 2017

I created a custom MarshalJSON for my struct and it outputs the wrong struct if I have customs MarshalJSON nested in my struct.

I'm trying to understand why it doesn't work as expected. I know that there are some limitations with type redefinition but it works well if I don't nest any struct with a custom MarshalJSON.

What version of Go are you using (go version)?

1.8

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

Linux

What did you do?

https://play.golang.org/p/Mp1ot20ILA

This example is just to be able to reproduce the problem. I know it doesn't make any sense the custom Copy type, but in a real problem, I would extend Copy type by adding custom fields.

What did you expect to see?

{"value":"A"}
{"value":"B","A":{"value":"A"}}
{"value":"C","A":{"value":"A"},"B":{"value":"B","A":{"value":"A"}}}

or at least

{"value":"A"}
{"value":"B"}
{"value":"C"}

What did you see instead?

{"value":"A"}
{"value":"A"}
{"value":"C","A":{"value":"A"},"B":{"value":"A"}}

The first line is ok.
The second line is completely wrong.
The third line is almost ok.

C has two nested objects with a custom marshal and it works almost good.
B has just one and it prints the output of A.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Sep 15, 2017

Note that we don't use the issue tracker to ask questions. Please see https://golang.org/wiki/Questions .

@alexandrevicenzi

This comment has been minimized.

Copy link
Author

commented Sep 15, 2017

In my opinion, it's a bug since it works for some cases.

@dsnet

This comment has been minimized.

Copy link
Member

commented Sep 15, 2017

I should note that Go 1.0 had the user's expected behavior:

{"value":"A"}
{"value":"B"}
{"value":"C"}

The current output has been the case since Go1.1.

@go101

This comment has been minimized.

Copy link

commented Sep 15, 2017

Maybe Go 1.0 is buggy. I feel the results of the later versions are right.

func (this *B) MarshalJSON() ([]byte, error) {
	type Copy B
	c := (*Copy)(this)
	return json.Marshal(c)
}

The type *Copy defined in (*B).MarshalJSON has one method,
this method comes from (*A).MarshalJSON.
(In a type definition, the new defined type will not retain the methods directly defined on the source type).
json.Marshal(c) will call c.A.MarshalJSON() consequently,
this is why the json.Marshal(c) in (*B).MarshalJSON will return []byte("{\"value\":\"A\"}").

The *Copy type in (*C).MarshalJSON has no methods for the collision of (*A).MarshalJSON and (*B).MarshalJSON.

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Mar 30, 2018

Doesn't seem to be anything to do here.

@golang golang locked and limited conversation to collaborators Mar 30, 2019

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.