To generate the JSON representation of a Go value, the encoding/json
package checks if the value implements the json.Marshaler
or the encoding.TextMarshaler
interfaces, and if so, they are used / called (in this order). This is documented at json.Marshal()
:
Marshal traverses the value v recursively. If an encountered value implements the Marshaler interface and is not a nil pointer, Marshal calls its MarshalJSON method to produce JSON. If no MarshalJSON method is present but the value implements encoding.TextMarshaler instead, Marshal calls its MarshalText method and encodes the result as a JSON string.
The json/encoding
package doesn't care about the String()
method. So if you want to control the JSON representation / output of your value (the Ticket
struct), implement json.Marshaler
on it (in which you may call String()
to your liking):
func (t Ticket) MarshalJSON() ([]byte, error) {
return []byte(`"` + t.String() + `"`), nil
}
Then the output will be as you desire:
{"Name":"John","Ticket":"New York - Washington"}
Try it on the Go Playground.
One thing to look out for: if the string
produced by Ticket.String()
would contain a quotation mark "
, the output would become invalid JSON, or more likely json.Marshal()
would return an error.
To take care of such escaping, best / easiest is to use the json
package itself: tell it to JSON-encode the string
result of Ticket.String()
:
func (t Ticket) MarshalJSON() ([]byte, error) {
return json.Marshal(t.String())
}
Now if we test it like this:
p.Name = "John"
p.Tkt.From = "New\" York" // CONTAINS QUOTE
p.Tkt.To = "Washington"
buf, err := json.Marshal(p)
fmt.Println(string(buf), err)
The output will still be a valid JSON (try it on the Go Playground):
{"Name":"John","Ticket":"New\" York - Washington"} <nil>