Problem:
How can we encode a struct with an embedded struct that has a custom MarshalJSON() method? The expected output is to preserve the custom marshaling of the embedded struct while also encoding the fields of the outer struct.
Example:
type Person struct { Name string `json:"name"` } type Employee struct { *Person JobRole string `json:"jobRole"` }
When the embedded Person 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), }) }
Marshaling an Employee instance breaks, resulting in:
{"name": "BOB"}
Solution:
Instead of implementing MarshalJSON() on Person, create a new Name type that implements MarshalJSON(). Then, modify Person to use this Name type:
type Name string func (n Name) MarshalJSON() ([]byte, error) { return json.Marshal(struct { Name string `json:"name"` }{ Name: strings.ToUpper(string(n)), }) } type Person struct { Name Name `json:"name"` }
This allows the custom marshaling logic to be applied to the Name field while still encoding the Employee fields as expected.
Generic Solution:
For a more generic solution, implement MarshalJSON() on the outer struct. While methods on the inner type are promoted to the outer type, the outer type can then unmarshal the result into a generic structure like map[string]interface{} and add its own fields.
Example:
type Person struct { Name string `json:"name"` } type Employee struct { *Person JobRole string `json:"jobRole"` } func (e *Employee) MarshalJSON() ([]byte, error) { b, err := e.Person.MarshalJSON() if err != nil { return nil, err } var m map[string]interface{} if err := json.Unmarshal(b, &m); err != nil { return nil, err } m["jobRole"] = e.JobRole return json.Marshal(m) }
The above is the detailed content of How to Correctly MarshalJSON() for Embedded Structs with Custom Marshaling?. For more information, please follow other related articles on the PHP Chinese website!