json

重写MarshalJSON

修改结构内某一属性

直接修改结构的值会引发无穷递归导致 panic:

  1. type User struct {
  2. Name string `json:"name"`
  3. }
  4. func (u User) MarshalJSON() ([]byte, error) {
  5. u.Name = "li"
  6. return json.Marshal(u) // panic
  7. }
  8. func TestPanic(t *testing.T) {
  9. res,err:= json.Marshal(User{Name: "wang"})
  10. fmt.Println(string(res), err)
  11. }

🌈 通过重命名一个 Alias 解决:

  1. type User struct {
  2. Name string `json:"name"`
  3. Gender string `json:"gender"`
  4. Role []string `json:"roles"`
  5. }
  6. func (u User) MarshalJSON() ([]byte, error) {
  7. type Alias User
  8. v := struct {
  9. Alias
  10. Age int `json:"age"`
  11. }{
  12. Alias: Alias(u),
  13. Age: 18,
  14. }
  15. if v.Role == nil {
  16. v.Role = []string{}
  17. }
  18. return json.Marshal(v)
  19. }
  20. func TestAlias(t *testing.T) {
  21. res, err := json.Marshal(User{Name: "wang", Gender: "man"})
  22. fmt.Println(string(res), err)
  23. // {"name":"wang","gender":"man","roles":[],"age":18} <nil>
  24. }

匿名字段重写MarshalJSON,顶层结构的MarshalJSON失效

常规 Alias 会导致最终调用匿名字段的 MarshalJSON:

  1. type User struct {
  2. Name string `json:"name"`
  3. }
  4. func (u User) MarshalJSON() ([]byte, error) {
  5. type Alias User
  6. v := struct {
  7. Alias
  8. Age int `json:"age"`
  9. }{
  10. Alias: Alias(u), Age: 18,
  11. }
  12. return json.Marshal(v)
  13. }
  14. type UserPermissions struct {
  15. User
  16. Permissions []string `json:"permissions"`
  17. }
  18. func (u UserPermissions) MarshalJSON() ([]byte, error) {
  19. type Alias UserPermissions
  20. v := struct {Alias}{Alias: Alias(u)}
  21. return json.Marshal(v)
  22. }
  23. func TestUserPermissions(t *testing.T) {
  24. res, err := json.Marshal(UserPermissions{User: User{Name: "wang"}, Permissions: []string{"one", "two"}})
  25. fmt.Println(string(res), err)
  26. // {"name":"wang","age":18} <nil>
  27. }

🌈 通过一个中间map来解决:
感谢:
Struct含有匿名字段,该匿名字段有MarshalJSON方法,导致Struct不能正确转换成json字符串!!
Idiomatic way to embed struct with custom MarshalJSON() method

  1. type User struct {
  2. Name string `json:"name"`
  3. }
  4. func (u User) MarshalJSON() ([]byte, error) {
  5. type Alias User
  6. v := struct {
  7. Alias
  8. Age int `json:"age"`
  9. }{
  10. Alias: Alias(u),
  11. Age: 18,
  12. }
  13. return json.Marshal(v)
  14. }
  15. type UserPermissions struct {
  16. User
  17. Permissions []string `json:"permissions"`
  18. }
  19. func (u UserPermissions) MarshalJSON() ([]byte, error) {
  20. pJSON, err := u.User.MarshalJSON()
  21. if err != nil {
  22. return nil, err
  23. }
  24. eJSON, err := json.Marshal(map[string]interface{}{
  25. "permissions": u.Permissions,
  26. })
  27. if err != nil {
  28. return nil, err
  29. }
  30. eJSON[0] = ','
  31. return append(pJSON[:len(pJSON)-1], eJSON...), nil
  32. }
  33. func TestUserPermissions(t *testing.T) {
  34. res, err := json.Marshal(UserPermissions{User: User{Name: "wang"}, Permissions: []string{"one", "two"}})
  35. fmt.Println(string(res), err)
  36. // {"name":"wang","age":18,"permissions":["one","two"]} <nil>
  37. }