Routing.Context.Write() not marshaling JSON as expected
Closed this issue · 2 comments
byanjiong commented
I have a struct Person
with custom JSON MarshalJSON
and UnmarshalJSON
methods. When I use the the Write()
in a routing handler, it skips these custom methods and use the default JSON marshal/unmarshal.
func GetPerson (c *routing.Context) error {
// ...
return c.Write(p) // print JSON with default JSON method, expect custom marshal to be used
}
However, if I wrap the struct in another struct or slice, e.g. :
type User struct {
UserID int `json:"userID"`
Details Person `json:"details"`
}
Or
[]Person{}
and c.Write(...)
these values, the custom marshal methods is used.
E.g.
func GetPerson (c *routing.Context) error {
u := User{}
// ... more code
return c.Write(u) // the custom marshal methods in Person is used (e.g. Birthday in Person have the correct time format)
}
func GetPeople (c *routing.Context) error {
people := []Person{}
// ... more code
return c.Write(people) // the custom marshal methods is being used too (e.g. time format is converted as expected)
}
Is it a bug?* I guess it is something related to http Writter*... Hmmm... may please have a look? :)
Note: the Person
struct is included below
type Person struct {
Name string `json:"name"`
Birthday time.Time `json:"birthday"`
Hobbies []Sharing `json:"hobbies"`
}
// MarshalJSON marshal struct.
// - Convert empty slice to "[]" instead of "null"
// - Custom manipulation to certain fields
// - Output time.Time in specific time format used by the app
func (m *Person) MarshalJSON() ([]byte, error) {
type Alias Person
if m.Hobbies == nil {
m.Hobbies = make([]Sharing, 0) //convert to empty array if slice is nil
}
return json.Marshal(&struct {
Name string `json:"name"`
Birthday string `json:"birthday"`
*Alias
}{
Name: "Oh, you need to guess it!", //custom manipulation
Birthday: app.TimeToString(m.Birthday), //change time format
Alias: (*Alias)(m),
})
}
// UnmarshalJSON unmarshal JSON to struct data
func (m *Person) UnmarshalJSON(data []byte) error {
type Alias Person
aux := &struct {
Birthday string `json:"birthday"`
*Alias
}{
Alias: (*Alias)(m),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
t, err = app.StringToTime(aux.Birthday)
if err != nil {
return err
}
m.Birthday = t
return nil
}
qiangxue commented
Declare your MarshalJSON
as this: func (m Person) MarshalJSON() ([]byte, error)
(the method is bound to the struct, not struct pointer)
byanjiong commented
OK, it works... many thanks... ^_^