I faced recently the following problem and have not found any solution. I have two struct types in Go, let us call them Parent and Child. Child has an anonymous field of the type *Parent. However, Parent has a field called "ID" which has the type of a third struct which type we will call "IDType" (in my real problem this is a dialect/sql.NullInt64). IDType has an int field and a bool field.
The problem is the following: Both, Parent and Child, implement MarshalJSON() because for Parent I only want the int field inside the JSON and for Child the same. However, it seems that both MarshalJSONs infer with the result that only the values of Parent are encoded in the final JSON.
Maybe a minimal example makes it easier to understand:
package main
import (
"encoding/json"
"fmt"
"os"
)
type IDType struct {
Value int
Valid bool
}
type Parent struct {
ID IDType `json:"id"`
SomeString string `json:"some_string"`
}
type Child struct {
*Parent
Status int `json:"status"`
}
func (parent *Parent) MarshalJSON() ([]byte, error) {
type Alias Parent
fmt.Println("Parent")
return json.Marshal(struct {
*Alias
ID int `json:"id"`
}{
Alias: (*Alias)(parent),
ID: parent.ID.Value,
})
}
func (child *Child) MarshalJSON() ([]byte, error) {
type Alias Child
fmt.Println("Child")
return json.Marshal(struct {
*Alias
Status int `json:"status"`
}{
Alias: (*Alias)(child),
Status: child.Status,
})
}
func main() {
ID := IDType{Value: 1, Valid: true}
parent := Parent{ID: ID, SomeString: "Hello"}
child := Child{Parent: &Parent{ID: ID, SomeString: "Hello"}, Status: 1}
json.NewEncoder(os.Stdout).Encode(&parent)
json.NewEncoder(os.Stdout).Encode(&child)
}
The output is:
Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1}
I expect something like:
Parent
{"some_string":"Hello","id":1}
Child
Parent
{"some_string":"Hello","id":1, "status": 1}
It looks you only define a custom marshaling logic because of the custom ID marshaling. Define your custom marshaling for the IDType
type only which is not embedded, so it won't cause any trouble marshaling the other types:
func (id *IDType) MarshalJSON() ([]byte, error) {
return json.Marshal(id.Value)
}
And no other custom marshaling are required. With this, the output will be:
{"id":1,"some_string":"Hello"}
{"id":1,"some_string":"Hello","status":1}
Try it on the Go Playground.