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

proposal: encoding/json: support json.Unmarshaler for decoding map keys #23455

rvcevans opened this issue Jan 16, 2018 · 4 comments


Copy link

Please answer these questions before submitting your issue. Thanks!

What did you do?

Unable to JSON marshal/unmarshal a custom primitive type as a map key unless the encoding Text interfaces are implemented instead of the JSON interfaces.

What did you expect to see?

The behaviour should be consistent for each implementation.

What did you see instead?

JSON unmarshalling fails if UnmarshalJSON is implemented instead of UnmarshalText. This is similar for marshalling.

System details

go version go1.9.2 linux/amd64
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build283259845=/tmp/go-build -gno-record-gcc-switches"
GOROOT/bin/go version: go version go1.9.2 linux/amd64
GOROOT/bin/go tool compile -V: compile version go1.9.2
uname -sr: Linux 4.11.9-300.fc26.x86_64
LSB Version:	:core-4.1-amd64:core-4.1-noarch:cxx-4.1-amd64:cxx-4.1-noarch:desktop-4.1-amd64:desktop-4.1-noarch:languages-4.1-amd64:languages-4.1-noarch:printing-4.1-amd64:printing-4.1-noarch
Distributor ID:	Fedora
Description:	Fedora release 26 (Twenty Six)
Release:	26
Codename:	TwentySix
/lib64/ GNU C Library (GNU libc) stable release version 2.25, by Roland McGrath et al.
gdb --version: GNU gdb (GDB) Fedora 8.0-13.fc26
Copy link

mvdan commented Jan 16, 2018

This seems to be enforced in the code on purpose:

// Check type of target:
//   struct or
//   map[T1]T2 where T1 is string, an integer type,
//             or an encoding.TextUnmarshaler
switch v.Kind() {
case reflect.Map:
        // Map key must either have string kind, have an integer kind,
        // or be an encoding.TextUnmarshaler.

And the godoc mentions the same:

To unmarshal a JSON object into a map, Unmarshal first establishes a map to use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal reuses the existing map, keeping existing entries. Unmarshal then stores key-value pairs from the JSON object into the map. The map's key type must either be a string, an integer, or implement encoding.TextUnmarshaler.

So this is "working as intended". I am not sure why it is this way, though. It seems like TextUnmarshaler support was added here: #12146

If you'd like to propose that json.Unmarshaler be obeyed here as well, I think that would be another proposal. But it doesn't seem like a bug to me, as it's documented.

@mvdan mvdan changed the title JSON: marshalling a custom type as a map key works only if the encoding Text interfaces are implemented. encoding/json: support json.Unmarshaler for decoding map keys Jan 16, 2018
Copy link

Closing, as this is working as intended.

Copy link

mvdan commented Jan 16, 2018

Well, I left the issue open in case OP wanted to convert it into a proposal, and since I wasn't 100% sure that this is what they meant originally (note how the original title said "marshaling", for example).

@titanous titanous reopened this Jan 16, 2018
@dsnet dsnet changed the title encoding/json: support json.Unmarshaler for decoding map keys proposal: encoding/json: support json.Unmarshaler for decoding map keys Jan 16, 2018
@gopherbot gopherbot added this to the Proposal milestone Jan 16, 2018
Copy link

Thanks. Having looked through the previous discussions the current behaviour does make sense. The example seems counterintuitive but consistency for the two interfaces wouldn't actually provide any new desired behaviour so I'll close this issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
None yet

No branches or pull requests

4 participants