Reputation: 3189
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
Upvotes: 4
Views: 1146
Reputation: 434685
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.
Upvotes: 6
Reputation: 100
The problem is that you are trying to map the value of spouse
in the json with a particular data type that doesn't match. As reported in this article, json uses empty interface to map generic data types to the right one used in the file.
The json package uses
map[string]interface{}
and[]interface{}
values to store arbitrary JSON objects and arrays; it will happily unmarshal any valid JSON blob into a plaininterface{}
value. The default concrete Go types are:
bool
for JSON booleans,float64
for JSON numbers,string
for JSON strings, andnil
for JSON null.
If you want to see it from another perspective, it means that you can't use anything other than these data types to map data in JSON. And your not empty interface isn't a valid type.
Upvotes: 1