I would like to unmarshal to struct Outer
defined as:
type Outer struct {
Inner
Num int
}
type Inner struct {
Data string
}
func (i *Inner) UnmarshalJSON(data []byte) error {
i.Data = string(data)
return nil
}
Using json.Unmarshal(data, &Outer{})
seems only to use Inner
's UnmarshalJSON
and ignores the Num
field: https://play.golang.org/p/WUBfzpheMl
I have an unwieldy solution where I set the Num
field manually, but I was wondering if anybody had a cleaner or simpler way to do it.
Thanks!
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"`
}
You shouldn't need an unmarshalling function
https://play.golang.org/p/-HZwX5-rPD
Edit: Here is a more complete 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.
One way to do this is to forgo the custom UnmarshalJSON
function entirely and just use the basic JSON notation, ie:
type Outer struct {
Inner
Num int `json:"num"`
}
type Inner struct {
Data string `json:"data"`
}
You lose some of the more granular capabilities you could have with a custom unmarshalling method, but when you're unmarshalling a struct with mostly primitive fields like strings, you really don't need to worry about that.
If you really need custom unmarshalling, you could use composition, and give the struct a custom json encoding tag and have the struct contain the fields you want to play with. So if data
is something that will contain multiple complex fields, you could just change Inner
to reflect those fields, like this:
type Outer struct {
Data Inner `json:"data"`
Num int `json:"num"`
}
type Inner struct {
Thing string `json:"thing"`
OtherThing int `json:"otherThing"`
}
Once again, this doesn't have a custom unmarshalling function, but that can be scraped together for Inner
easily enough. (Personally, I'd forgo the use of custom unmarshal functions entirely in any given case and just use encoding tags unless I absolutely had to use the unmarshalling function.)
Faced same issue. One solution is to unmarshal twice for each sub structs. Eg
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.
Actually you not need explicit field, you need properly Marshal/UnMarshal
Example: https://play.golang.org/p/mWPM7m44wfK
package main
import (
"encoding/json"
"fmt"
)
type Outer struct {
Inner
Num int `json:"Num"`
}
type Inner struct{ Data string }
type InnerRaw struct {Data string}
func (i *Inner) UnmarshalJSON(data []byte) error {
ir:=&InnerRaw{}
json.Unmarshal(data, ir)
i.Data = ir.Data
return nil
}
func main() {
x := Outer{}
data := []byte(`{"Num": 4, "Data":"234"}`)
_ = json.Unmarshal(data, &x)
fmt.Printf("%+v\n", x)
js, _:=json.Marshal(x)
fmt.Printf("JSON:%s", string(js))
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.