Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would adding a func in an interface cause json.Unmarshal to fail?

Tags:

json

go

Why does this fail with the error :

json: cannot unmarshal object into Go struct field Person.spouse of type main.Spouse

type Spouse interface {
    Name() // Adding this causes an error
}

type Address interface {
}

type Person struct {
    Name string   `json:"name"`
    A    *Address `json:"address"`
    S    *Spouse  `json:"spouse"`
}

func main() {
    b := []byte(`{
     "name":"sarah", 
     "address":{
         "street":"101 main" 
         }, 
     "spouse":{
         "name":"joe"
         }
     }
    `)

    p := &Person{}
    if err := json.Unmarshal(b, p); err != nil {
        fmt.Printf("%s", err)
    }
}

Looking at the docs, I don't see why adding a function in an interface would cause an error. I was expecting json.Unmarshal to simply ignore the Name() function since it's not part of the list processed by json.Unmarshal.

Here is the code in go playground.

go version go1.10 darwin/amd64

like image 484
rexposadas Avatar asked Oct 20 '25 05:10

rexposadas


1 Answers

From the fine manual:

func Unmarshal
[...]
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:

bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null

You're trying to unmarshal a JSON object into an interface so the value behind that interface is going to be a map[string]interface{} to represent the key/value pairs. But map[string]interface{} doesn't have a Name() method so it doesn't implement your Spouse interface.

If we simplify your example a little and get rid of the Name() method we can see what's going on:

type Spouse interface {
}

type Person struct {
    S *Spouse `json:"spouse"`
}

func main() {
    b := []byte(`{"spouse":{ "name":"joe" } }`)

    p := &Person{}
    if err := json.Unmarshal(b, p); err != nil {
        fmt.Printf("%s", err)
    }
    spouse := (*p.S).(map[string]interface{})
    fmt.Printf("%+v\n", spouse)
}

spouse is a map[string]interface{} as documented.

like image 163
mu is too short Avatar answered Oct 21 '25 20:10

mu is too short



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!