Given the following structs:
type Person {
Name string `json:\"name\"`
}
type Employee {
Person
JobRole string `json:\"jobRole\"`
}
<
While this produces a different output than what the OP wants, I think it is still useful as a technique to prevent MarshalJSON
of embedded structs from breaking the marshaling of structs that contain them.
There is a proposal for encoding/json to recognize an inline option in struct tags. If that ever gets implemented, then I think avoiding embedding structs for cases like in OP's example might be the best bet.
Currently, a reasonable workaround was described in a comment on the Go issue tracker and is the basis for this answer. It consists of defining a new type that will have the same memory layout as the original struct being embedded, but none of the methods:
https://play.golang.org/p/BCwcyIqv0F7
package main
import (
"encoding/json"
"fmt"
"strings"
)
type Person struct {
Name string `json:"name"`
}
func (p *Person) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Name string `json:"name"`
}{
Name: strings.ToUpper(p.Name),
})
}
// person has all the fields of Person, but none of the methods.
// It exists to be embedded in other structs.
type person Person
type EmployeeBroken struct {
*Person
JobRole string `json:"jobRole"`
}
type EmployeeGood struct {
*person
JobRole string `json:"jobRole"`
}
func main() {
{
p := Person{"Bob"}
e := EmployeeBroken{&p, "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
}
{
p := Person{"Bob"}
e := EmployeeGood{(*person)(&p), "Sales"}
output, _ := json.Marshal(e)
fmt.Printf("%s\n", string(output))
}
}
Outputs:
{"name":"BOB"}
{"name":"Bob","jobRole":"Sales"}
The OP wants {"name":"BOB","jobRole":"Sales"}
. To achieve that, one would need to "inline" the object returned by Person.MarshalJSON
into the object produced by Employee.MashalJSON
, excluding the fields defined in Person
.