Given the following structs:
type Person struct {
Name string `json:"name"`
}
type Employee struct {
*Person
JobRole string `json:"jobRole"`
}
I can easily marshal an Employee to JSON as expected:
p := Person{"Bob"}
e := Employee{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
Output:
{"name":"Bob","jobRole":"Sales"}
But when the embedded struct has a custom MarshalJSON()
method...
func (p *Person) MarshalJSON() ([]byte,error) {
return json.Marshal(struct{
Name string `json:"name"`
}{
Name: strings.ToUpper(p.Name),
})
}
it breaks entirely:
p := Person{"Bob"}
e := Employee{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
Now results in:
{"name":"BOB"}
(Note the conspicuous lack of jobRole
field)
This is easily anticipated... the embedded Person
struct implements the MarshalJSON()
function, which is being called.
The trouble is, it's not what I want. What I want would be:
{"name":"BOB","jobRole":"Sales"}
That is, encode Employee
's fields normally, and defer to Person
's MarshalJSON()
method to marshal its fields, and hand back some tidy JSON.
Now I could add a MarshalJSON()
method to Employee
as well, but this requires that I know that the embedded type implements MarshalJSON()
as well, and either (a) duplicate its logic, or (b) call Person
's MarshalJSON()
and somehow manipulate its output to fit where I want it. Either approach seems sloppy, and not very future proof (what if an embedded type I don't control some day adds a custom MarshalJSON()
method?)
Are there any alternatives here that I haven't considered?
MarshalJSON
returned an array? There's no way to merge that into an object. Composition is hard. – Dissect