Suppose I've written the following code snippet. Full code on the playground here for those inclined.
type Book struct { Title string Author string } func main() { ms := Book{"Catch-22", "Joseph Heller"} out, err := json.MarshalIndent(ms, "", " ") if err != nil { log.Fatalln(err) } fmt.Println(string(out)) }
This code outputs the following, exactly as I'd expect:
{ "Title": "Catch-22", "Author": "Joseph Heller" }
Suppose for a moment I wanted to add a field to the JSON output without including it in the Book
struct. Perhaps a genre:
{ "Title": "Catch-22", "Author": "Joseph Heller", "Genre": "Satire" }
Can I use MarshalJSON()
to add an arbitrary field to the JSON payload on Marshal()
? Something like:
func (b *Book) MarshalJSON() ([]byte, error) { // some code }
Other answers make me think this should be possible, but I'm struggling to figure out the implementation.
To parse JSON, we use the Unmarshal() function in package encoding/json to unpack or decode the data from JSON to a struct. Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. Note: If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.
To unmarshal a JSON array into a slice, Unmarshal resets the slice length to zero and then appends each element to the slice. As a special case, to unmarshal an empty JSON array into a slice, Unmarshal replaces the slice with a new empty slice.
Omitempty tag `json:,omitempty` is a json tag for a field in a struct. When unmarshalling json data into a struct, if that particular field is empty, the field would be ignored. Without the omitempty tag, a default value will be used.
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
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", }) }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With