We need to use a custom unmarshaler for a struct nested in multiple other structs which don't require a custom unmarshaler. We have lots of structs similar to B
struct defined below (similar as in nesting A
). The code's output is true false 0
(expected true false 2
). Any ideas?
Go Playground example here.
package main
import (
"fmt"
"encoding/json"
)
type A struct {
X bool `json:"x"`
Y bool `json:"y"`
}
type B struct {
A
Z int `json:"z"`
}
func (a *A) UnmarshalJSON(bytes []byte) error {
var aa struct {
X string `json:"x"`
Y string `json:"y"`
}
json.Unmarshal(bytes, &aa)
a.X = aa.X == "123"
a.Y = aa.Y == "abc"
return nil
}
const myJSON = `{"x": "123", "y": "fff", "z": 2}`
func main() {
var b B
json.Unmarshal([]byte(myJSON), &b)
fmt.Print(b.X," ",b.Y," ",b.Z)
}
EDIT: question was marked as duplicate here but making A
an explicit field will make our API cluttered. Also after making A
an explicit field the result is false false 2
so it does not help at all.
Since B
embeds A
, A.UnmarshalJSON()
is exposed as B.UnmarshalJSON()
. Due to that, B
implements json.Unmarshaler
and as a result json.Unmarshal()
calls B.UnmarshalJSON()
which only unmarshal's A
's fields. That's the reason B.Z
does not get set from the JSON.
This is the easiest way I could think of to get it working in accordance with your constraint of not changing the data types in A
:
With the new B.UnmarshalJSON()
method, you now have full control to unmarshal the fields outside of A
as well.
type A struct {
X bool `json:"x"`
Y bool `json:"y"`
}
func (a *A) UnmarshalJSON(bytes []byte) error {
// the special unmarshalling logic here
}
type C struct {
Z int `json:"z"`
}
type B struct {
A
C
}
func (b *B) UnmarshalJSON(bytes []byte) error {
if err := json.Unmarshal(bytes, &b.A); err != nil {
return err
}
if err := json.Unmarshal(bytes, &b.C); err != nil {
return err
}
return nil
}