json unmarshal embedded struct

This is happening because Inner is being embedded in Outer. That means when json library calls unmarshaler on Outer, it instead ends up calling it on Inner.

Therefore, inside func (i *Inner) UnmarshalJSON(data []byte), the data argument contains the entire json string, which you are then processing for Inner only.

You can fix this by making Inner explicit field in Outer

Outer struct {
    I Inner // make Inner an explicit field
    Num int `json:"Num"`
}

Working example


Just delete UnmarshalJSON in your example because it's used in unmarshaling of Outer since Inner is inlined. Otherwise, you need to override it if you want to do something custom.

https://play.golang.org/p/D6V6vKpx9J


Faced same issue. One solution is to unmarshal twice for each sub structs. E.g.

type Inner struct {
        Data string
}

type NumField struct {
        Num int
}

type Outer struct {
        Inner
        NumField
}

func (i *Inner) UnmarshalJSON(data []byte) error {
        i.Data = string(data)
        return nil
}

func (o *Outer) UnmarshalJSON(data []byte) error {
        if err := json.Unmarshal(data, &o.Inner); err != nil {
                return err
        }
        if err := json.Unmarshal(data, &o.NumField); err != nil {
                return err
        }
        return nil
}

func main() {
        x := Outer{}
        data := []byte(`{"Num": 4}`)
        _ = json.Unmarshal(data, &x)
        fmt.Printf("%#v\n", x)
}

This requires moving the extra fields into a separate struct.