Reputation: 344
I have created a new declared type and added a method to marshal the value into JSON
type TextOutput string
func (t *TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data": "%s"}`, t)), nil
}
When I try to marshal an instance of the type I get the raw value returned. What am I missing?
var t TextOutput
t = `Test test`
output, err := json.Marshal(t)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(string(output))
}
// prints Test Test. Expected {"data": "Test test"}
Upvotes: 1
Views: 770
Reputation: 496
The root of the problem stems from how interfaces in Go are implicitly satisfied.
In this particular case, the json.Marshal
method uses type assertion at runtime to see if the given value implements json.Marshaler
. Effective Go mentions this very case.
You could have satisfied the json.Marshaler
for the *TextOutput
type using a pointer-receiver like so:
func (t *TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data":"%s"}`, *t)), nil
}
And for this to work properly, pass the reference to the json.Marshal
function:
var t TextOutput
t = `Test test`
output, err := json.Marshal(&t)
However, implementing it using a value-receiver ensures that both TextOutput
and *TextOutput
types implement json.Marshaler
func (t TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data": "%s"}`, t)), nil
}
Upvotes: 1
Reputation: 4791
You have to define the MarshalJSON
interface as a non-pointer.
func (t TextOutput) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`{"data": "%s"}`, t)), nil
}
Play Link: https://play.golang.org/p/lLK6zsAkOi
Output:
{"data":"Test test"}
Upvotes: 2