encoding/json
パッケージのMarshalJSON処理を実装する方法をメモ
このメソッドを実装すると、構造体をJSONに変換する際に、変換結果を変更することができる。
今回やりたかったのは、空のStructがプロパティとして埋め込まれている場合、そのプロパティは omitempty
が効かない。
下記の場合、Group
構造体が User
構造体に埋め込まれているが、omitempty
しても意味がない。
type (
Group struct {
Name string `json:,omitempty`
}
User struct {
Group Group `json:",omitempty"`
Name string `json:",omitempty"`
Age int `json:",omitempty"`
UpdatedAt time.Time `json:",omitempty"`
}
)
func main() {
u := User{
Name: "Hoge太郎",
Age: 31,
UpdatedAt:time.Date(2017, 6, 1, 1, 0, 0, 0, time.UTC),
}
userJson, _ := json.Marshal(u)
fmt.Println(string(userJson))
}
出力結果
{"Group":{"Name":""},"Name":"Hoge太郎","Age":31,"UpdatedAt":"2017-06-01T01:00:00Z"}
omitempty
されず "Group":{"Name":""}
が出力されてしまっている。
場合によっては害を及ぼす。
この場合、json.Marshaler
を User
構造体に実装させ、MarshalJSON
JSON用の構造体をメソッド内で再定義する。
ただし、全てのプロパティを定義するのは面倒なので、オリジナルの構造体を埋め組むが、エイリアスとして組み込まなければMarshalJSONメソッドが無限ループに陥ってしまう。
type (
Group struct {
Name string `json:,omitempty`
}
User struct {
Group Group `json:",omitempty"`
Name string `json:",omitempty"`
Age int `json:",omitempty"`
UpdatedAt time.Time `json:",omitempty"`
}
)
// JSON化処理を変更する(encoding/json.Marshalerを実装)
func (u User) MarshalJSON()([]byte, error){
type Alias User
// 全く新しい構造体を定義
// 全てのプロパティを定義するのは面倒なので、オリジナルの構造体を埋め組む
// ただし、エイリアスとして組み込まなければMarshalJSONメソッドが無限ループに陥ってしまう
return json.Marshal(&struct {
Alias
Group bool `json:",omitempty"`
}{
Alias: (Alias)(u),
})
}
func main() {
u := User{
Name: "Hoge太郎",
Age: 31,
UpdatedAt:time.Date(2017, 6, 1, 1, 0, 0, 0, time.UTC),
}
userJson, _ := json.Marshal(u)
fmt.Println(string(userJson))
}
出力結果
{"Name":"Hoge太郎","Age":31,"UpdatedAt":"2017-06-01T01:00:00Z"}
この方法を応用して、日付のフォーマットを変更したり、追加でプロパティを増やしたりもできる。