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

Can't use json.Unmarshal on self inside an UnmarshalText function #28119

Closed
CrushedPixel opened this issue Oct 10, 2018 · 6 comments
Closed

Can't use json.Unmarshal on self inside an UnmarshalText function #28119

CrushedPixel opened this issue Oct 10, 2018 · 6 comments

Comments

@CrushedPixel
Copy link

An encoding.TextUnmarshaler can't use the encoding/json and encoding/xml packages to deserialize a json/xml representation of itself. This is probably because encoding/json treats types implementing encoding.TextUnmarshaler in a special way.

This simple project reproduces the issue: https://play.golang.org/p/huW7nqPqNCW

When unmarshaling, the following error is returned:

json: cannot unmarshal object into Go value of type *main.Test

Unmarshaling the json representation into a map[string]interface{} works just fine.

@ianlancetaylor
Copy link
Contributor

Your code can't work. You are implementing the unmarshaling of Test by unmarshaling into Test. That will simply lead to an infinite recursion. The package is saving you from that by returning an error.

Do something like this instead: https://play.golang.org/p/KvZogax4MRQ

@CrushedPixel
Copy link
Author

Can you elaborate why encoding/json looks at the UnmarshalText implementation when unmarshaling an object?

@ianlancetaylor
Copy link
Contributor

It's possible that I've misdescribed what the encoding/json package is doing, but as far as I can see it's still the case that your original program can't work.

@CrushedPixel
Copy link
Author

I see no reason why encoding/json would need to look at its UnmarshalText function when mapping a json object to a struct. Nothing in the documentation indicates this, and I honestly expected it to perform the json parsing as usual, without looking at UnmarshalText. If I was implementing json.Unmarshaler, I'd be on your side with the infinite recursion, but not like this.

@ianlancetaylor
Copy link
Contributor

OK, maybe I see what you mean. Given a type that implements the UnmarshalText method and an input that is not a JSON quoted string, we can either ignore the UnmarshalText or we can return an error. Since UnmarshalText was implemented, we've returned an error (https://golang.org/cl/12703043). I suppose that perhaps the question is which operation is less confusing: honoring UnmarshalJSON but ignoring UnmarshalText, or honoring UnmarshalJSON and giving an error for UnmarshalText.

@CrushedPixel
Copy link
Author

IMHO, it the latter makes more sense - when unmarshaling a JSON value, I'd assume that the decoder would look at the function that was specifically designed to handle JSON representations (json.Unmarshaler), and not the generic function unmarshaling it from an arbitrary text format.

Suppose I need to provide a type implementing encoding.TextMarshaler and encoding.TextUnmarshaler to a library's function, but don't want to serialize/deserialize the struct's fields myself, I expected to be able to simply call the json.Marshal/json.Unmarshal functions when implementing these interfaces, but due to this unmarshaling behaviour, that's not possible.

@golang golang locked and limited conversation to collaborators Oct 11, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants