Can I use MarshalJSON to add arbitrary fields to a json encoding in golang?
This is one method of handling it:
type Object struct {
A string
B int
Extra map[string]interface{} `json:"-"`
}
func (o Object) MarshalJSON() ([]byte, error) {
type Object_ Object
b, err := json.Marshal(Object_(o))
if err != nil {
return nil, err
}
if o.Extra == nil || len(o.Extra) == 0 {
return b, nil
}
m, err := json.Marshal(o.Extra)
if err != nil {
return nil, err
}
if len(b) == 2 {
return m, nil
} else {
b[len(b)-1] = ','
return append(b, m[1:]...), nil
}
}
You can add whatever additional fields to the Extra
map and they will appear without nesting in the output.
Go Playground
One possible answer to this question is a struct literal (code here), although I'm hoping for something a bit more general, which doesn't require remapping all of the struct's fields:
func (b *Book) MarshalJSON() ([]byte, error) {
return json.Marshal(struct{
Title string
Author string
Genre string
} {
Title: b.Title,
Author: b.Author,
Genre: "Satire",
})
}
Marshalling a map
is another way around the problem.
tmap := make(map[string]interface{})
tmap["struct"] = struct {
StructValue string `json:"struct_value"`
}{
"Value 02",
}
tmap["string"] = "Value 01"
out, err := json.MarshalIndent(tmap, "", " ")
if err != nil {
log.Fatalln(err)
}
fmt.Println(string(out))
This will output:
{
"string": "Value 01",
"struct": {
"struct_value": "Value 02"
}
}
Where you have many arbitrary key names this could be a good solution.
Playground: https://play.golang.org/p/Umy9rtx2Ms
Here's a better answer than my previous one.
type FakeBook Book
func (b Book) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
FakeBook
Genre string
}{
FakeBook: FakeBook(b),
Genre: "Satire",
})
}
Since anonymous struct fields are "merged" (with a few additional considerations) we can use that to avoid remapping the individual fields. Note the use of the FakeBook
type to avoid the infinite recursion which would otherwise occur.
Playground: http://play.golang.org/p/21YXhB6OyC