概要
error タイプは json.Marshal
すると {}
に変換されます
このまま json.Unmarshal
すると {}
は error タイプでないと言われてエラーになります
しかし JSON でエラーを管理したい場合があります
そんな場合はエラーメッセージだけを JSON で管理するようにしましょう
環境
- macOS 10.14.6
- go 1.11.5
エラーが発生するコード
package main
import (
"encoding/json"
"errors"
"fmt"
)
type Profile struct {
Name string `json:"name"`
Age int `json:"age"`
Err error `json:"error"`
}
func main() {
p := Profile{
Name: "hawksnowlog",
Age: 99,
Err: errors.New("test"),
}
j, err := json.Marshal(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(j))
p2 := Profile{}
err = json.Unmarshal(j, &p2)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p2.Name)
fmt.Println(p2.Age)
fmt.Println(p2.Err)
}
=> {"name":"hawksnowlog","age":99,"error":{}}
素直に実行するとこんな感じで JSON が表示されそのあとパースエラーが表示されます
対応したコード
今回は ErrMsg
というフィールドを構造体に一つ追加しそのフィールドを JSON 用のフィールドとして使います
そして MarshalJSON
と UnmarshalJSON
を実装することで JSON <-> struct
の相互変換時にエラーの情報を復元します
また json:"-"
をフィールドに追加することでそのフィールドを JSON に含めないようにします
package main
import (
"encoding/json"
"errors"
"fmt"
)
type Profile struct {
Name string `json:"name"`
Age int `json:"age"`
Err error `json:"-"`
ErrMsg string `json:"error"`
}
func (p *Profile) UnmarshalJSON(b []byte) error {
type Alias Profile
p2 := Alias{}
err := json.Unmarshal(b, &p2)
if err != nil {
return err
}
p.Name = p2.Name
p.Age = p2.Age
p.Err = errors.New(p2.ErrMsg)
return nil
}
func (p Profile) MarshalJSON() ([]byte, error) {
type Alias Profile
p2 := Alias{
Name: p.Name,
Age: p.Age,
Err: p.Err,
ErrMsg: p.Err.Error(),
}
ret, err := json.Marshal(p2)
if err != nil {
return nil, err
}
return ret, nil
}
func main() {
p := Profile{
Name: "hawksnowlog",
Age: 99,
Err: errors.New("test"),
}
j, err := json.Marshal(p)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(j))
p2 := Profile{}
err = json.Unmarshal(j, &p2)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(p2.Name)
fmt.Println(p2.Age)
fmt.Println(p2.Err)
}
=> {"name":"hawksnowlog","age":99,"error":"test"}
となり構造体もちゃんと復元されます
また type をエイリアスしてあげることも大事でこれをしないと json.Marshal
や json.Unmarshal
をコールしたときに無限ループになるので注意しましょう
0 件のコメント:
コメントを投稿