Custom MarshalJSON() never gets called in Go

go, json, marshalling

Solution

In this part of the code, `ms` gets copied into an `interface{}` variable:

// Trying another method (UNSUCCESSFUL)
if ret, err := json.Marshal(ms); err != nil {

The problem is that this variable does not implement the `json.Marshaler` interface, since `MarshalJSON` is not in the method set for `myStruct` (only for `*myStruct`).

The fix is to either (a) make your `MarshalJSON` method take a non-pointer receiver (which will mean it gets a copy of the struct: possibly costly if it is large), or (b) marshal a pointer to the struct (as Kavu mentioned in a comment).

The reason for this behaviour is that Go doesn't let you take a pointer to the value stored inside an interface variable, instead requiring you to make a copy of the value whenever you want to access it. While the language has syntactic sugar to convert `ms.MarshalJSON()` into `(&ms).MarshalJSON()` as a way to access the method with a pointer receiver, this can not be done for a value stored in an interface variable. For this reason, the method is not considered to be in its method set.

Problem

I've written custom versions of `MarshalJSON` and `UnmarshalJSON`. My `UnmarshalJSON` gets called the way I want it to, but I can't get it to work with `MarshalJSON`. Here's code that summarizes my problem: ``` package main import ( "bytes" "encoding/json" "fmt" "log" "os" ) type myStruct struct { Data string `json:"data"` } func (s *myStruct) MarshalJSON() ([]byte, error) { return []byte(`{"data":"charlie"}`), nil } func (s *myStruct) UnmarshalJSON(b []byte) error { // Insert the string directly into the Data member return json.Unmarshal(b, &s.Data) } func main() { // Create a struct with initial content "alpha" ms := myStruct{"alpha"} // Replace content with "bravo" using custom UnmarshalJSON() (SUCCESSFUL) if err := json.NewDecoder(bytes.NewBufferString(`"bravo"`)).Decode(&ms); err != nil { log.Fatal(err) } // Use custom MarshalJSON() to get "charlie" back (UNSUCCESSFUL) if err := json.NewEncoder(os.Stdout).Encode(ms); err != nil { log.Fatal(err) } // Trying another method (UNSUCCESSFUL) if ret, err := json.Marshal(ms); err != nil { log.Fatal(err) } else { fmt.Println(string(ret)) } // Verify that the Marshaler interface is correctly implemented var marsh json.Marshaler marsh = &ms ret, _ := marsh.MarshalJSON() fmt.Println(string(ret)) // Prints "charlie" } ``` In short, the program encodes the `struct` "automatically" in two ways, and then finally calls `MarshalJSON` manually. The response I want is `"charlie"`. Running the code generates the following output: ``` {"data":"bravo"} {"data":"bravo"} {"data":"charlie"} ``` Try it at Go Playground: http://play.golang.org/p/SJ05S8rAYN

Original source