unmarshal handling golang examples deserialize json go marshalling

handling - Custom MarshalJSON() nunca recibe una llamada en Go



json stringify golang (1)

He escrito versiones personalizadas de MarshalJSON y UnmarshalJSON . Mi UnmarshalJSON se llama de la manera que quiero, pero no puedo hacerlo funcionar con MarshalJSON . Aquí está el código que resume mi problema:

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" }

En resumen, el programa codifica la struct "automáticamente" de dos maneras y, finalmente, llama a MarshalJSON manualmente. La respuesta que quiero es "charlie" . Ejecutar el código genera el siguiente resultado:

{"data":"bravo"} {"data":"bravo"} {"data":"charlie"}

Pruébelo en Go Playground: http://play.golang.org/p/SJ05S8rAYN


En esta parte del código, ms se copia en una variable de interface{} :

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

El problema es que esta variable no implementa la interfaz json.Marshaler , ya que MarshalJSON no está en el conjunto de métodos para myStruct (solo para *myStruct ).

La solución es (a) hacer que su método MarshalJSON tome un receptor sin puntero (lo que significa que obtiene una copia de la estructura: posiblemente sea costoso si es grande), o (b) marque un puntero a la estructura (como Kavu mencionado en un comentario).

El motivo de este comportamiento es que Go no le permite llevar un puntero al valor almacenado dentro de una variable de interfaz, en lugar de eso, le exige que haga una copia del valor cada vez que desee acceder a él. Si bien el lenguaje tiene azúcar sintáctico para convertir ms.MarshalJSON() en (&ms).MarshalJSON() como una forma de acceder al método con un receptor de puntero, esto no puede hacerse para un valor almacenado en una variable de interfaz. Por esta razón, no se considera que el método esté en su conjunto de métodos.