Goでsql.NullStringを含む構造体をjson.Marshalする方法
以下を参考にしたがうまくできなかったので、変更点を記載。
参考
http://okamuuu.hatenablog.com/entry/2016/12/20/150339
以下の構造体 A
があったとします
type A struct {
ID int `json:"id"`
Title string `json:"title"`
Desc sql.NullString `json:"desc"`
}
sql.NullString
を使うケースとしては、 NULLを許容
するときです。
で、これを json.Marshal
すると、
"desc" : { "String" : "", "Valid" : false }
という感じになってしまいます。
json.Marshal
のソースを見ると、 MarshalJSON()
というinterfaceを持っていれば、
それを実行するというふうになっています。
sql.NullString
は、MarshalJSON()
を持たないので、
以下のようにカスタムで NullString
と言う感じの構造体を作って、それを定義してあげます。
type NullString struct {
sql.NullString
}
func (s NullString) MarshalJSON() ([]byte, error) {
return json.Marshal(s.String)
}
func (s *NullString) UnmarshalJSON(data []byte) error {
var str string
if err := json.Unmarshal(data, &str); err != nil {
return err
}
s.String = str
s.Valid = str != ""
return nil
}
それで、今回のポイントは1つで、
func (s NullString) MarshalJSON()
この部分です。
参考にした記事とかでは、
func (s *NullString) MarshalJSON()
というふうになっていて、すなわち、レシーバーがポインタになっているわけです。
このとき、jsonにしたい構造体で、
[]NullString
というslice型の場合は、ちゃんと MarshalJSON
を実行してくれますが、
NullString
という通常の型の場合は、実行してくれません。
自分は、ここで躓きました。。
で、結局正しいのはなにかというと、
Marshalする場合は、レシーバーをポインタにしない
func (s NullString) MarshalJSON()
で正しく動きます。