-
Notifications
You must be signed in to change notification settings - Fork 18k
encoding/json: custom unmarshaler is ignored for map #34437
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
Comments
This sounds related to @mvdan's last comment on a similar issue: #28189 (comment) In this case, var m MyString
v := reflect.ValueOf(m)
fmt.Println(v.Kind()) // string
// Even though MyString implements a custom TextUnmarshaler, the ValueOf.Kind check is used first.
var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
p1 := make(map[MyString]string)
v2 := reflect.ValueOf(p1)
fmt.Println(reflect.PtrTo(v2.Type().Key()).Implements(textUnmarshalerType)) // true See related code here: go/src/encoding/json/decode.go Lines 633 to 637 in dfbc9c8
And here: go/src/encoding/json/decode.go Lines 776 to 777 in dfbc9c8
Because the string key case is checked first, your custom As a workaround, you can define a custom map type that defines UnmarshalJSON and does the work you want, but it will not be as clean as you expect in your example. I'll let the domain experts take over from here. |
Playing around with var m MyString
var x string
fmt.Println(reflect.ValueOf(m).Type().Name()) // returns "MyString"
fmt.Println(reflect.ValueOf(x).Type().Name()) // returns "string" It could be a bit hacky ... |
I'm pretty sure this is working as intended:
Note that it mentions |
@mvdan thanks for pointing out the doc. However, it doesn't seem working per the below code. package main
import (
"encoding/json"
"fmt"
"strings"
)
type MyString string
func (m *MyString) UnmarshalText(text []byte) error {
fmt.Println("not invoked")
*m = MyString(strings.ToLower(string(text)))
return nil
}
func main() {
var p map[MyString]string
_ = json.Unmarshal([]byte(`
{
"KEY1": "1",
"KEY2": "2"
}
`), &p)
fmt.Println(p) // INCORRECT output: map[KEY1:1 KEY2:2] but expected: map[key1:1 key2:2]
} Am i missing anything? |
The problem is that
Even |
Change https://golang.org/cl/200237 mentions this issue: |
If i use a custom type for
string
implementingUnmarshaler
interface and use it as key type in a map, the unmarshaling seems not working as expected.The text was updated successfully, but these errors were encountered: