自定义将扁平的 JSON 转换为嵌套结构的反序列化方法

huangapple go评论122阅读模式
英文:

Custom unmarshalling from flat json to nested struct

问题

假设我有两个相关的结构体,如下所示:

  1. type SecretUser struct {
  2. UserInfo `json:"userInfo"`
  3. Password string `json:"password"`
  4. }
  5. type UserInfo struct {
  6. FirstName string `json:"firstName"`
  7. LastName string `json:"lastName"`
  8. Email string `json:"email"`
  9. }

我收到的JSON数据如下所示:

  1. {
  2. "firstName": "nice",
  3. "lastName": "guy",
  4. "email": "nice@guy.co.uk",
  5. "password": "abc123"
  6. }

我想将这个JSON数据解组成一个SecretUser结构体。有没有比下面这种方法更好的方式?

  1. func (u *User) UnmarshalJSON(data []byte) error {
  2. var objmap map[string]*json.RawMessage
  3. var password string
  4. var err error
  5. err = json.Unmarshal(data, &objmap)
  6. if err != nil {
  7. return err
  8. }
  9. if err := json.Unmarshal(data, &u.UserInfo); err != nil {
  10. return err
  11. }
  12. err = json.Unmarshal(*objmap["password"], &password)
  13. if err != nil {
  14. return err
  15. }
  16. u.Password = password
  17. return nil
  18. }

基本上,我将JSON数据部分解组成一个UserInfo结构体,然后再次读取它以提取密码。我不想为了清晰地解组这个JSON数据而创建另一个结构体,也不想使用外部库(除非它是标准库的一部分)。有没有更清晰/高效的方法来做到这一点,而不需要两次读取JSON数据或手动从映射中设置每个字段?

英文:

Lets say I have two struct that are related like this:

  1. type SecretUser struct {
  2. UserInfo `json:"userInfo"`
  3. Password string `json:"password"`
  4. }
  5. type UserInfo struct {
  6. FirstName string `json:"firstName"`
  7. LastName string `json:"lastName"`
  8. Email string `json:"email"`
  9. }

And I receive a JSON in this form:

  1. {
  2. "firstName": "nice",
  3. "lastName":"guy",
  4. "email":"nice@guy.co.uk",
  5. "password":"abc123"
  6. }

I want to unmarshall this JSON into a SecretUser. Is there a better way than doing it like this?

  1. func (u *User) UnmarshalJSON(data []byte) error {
  2. var objmap map[string]*json.RawMessage
  3. var password string
  4. var err error
  5. err = json.Unmarshal(data, &objmap)
  6. if err != nil {
  7. return err
  8. }
  9. if err := json.Unmarshal(data, &u.UserInfo); err != nil {
  10. return err
  11. }
  12. err = json.Unmarshal(*objmap["password"], &password)
  13. if err != nil {
  14. return err
  15. }
  16. u.Password = password
  17. return nil
  18. }

Basically, I partially unmarshall the JSON into a UserInfo struct and then read it again to extract the password. I don't want to create another struct for just unmarshalling this JSON cleanly or use an external library (unless it's part of the standard). Is there a more clean/efficient way of doing this, without reading the JSON twice or setting every field manually from a map?

答案1

得分: 1

只需将UserData包含在SecretUser结构体中,并且不为其指定json标签。

  1. type UserInfo struct {
  2. FirstName string `json:"firstName"`
  3. LastName string `json:"lastName"`
  4. Email string `json:"email"`
  5. }
  6. type SecretUser struct {
  7. UserInfo
  8. Password string `json:"password"`
  9. }
  10. func main() {
  11. data := []byte(`{"firstName": "nice","lastName":"guy","email":"nice@guy.co.uk","password":"abc123"}`)
  12. var u SecretUser
  13. json.Unmarshal(data, &u)
  14. fmt.Println(u)
  15. }

Go Play Space 示例

英文:

Simply include the UserData into the SecretUser struct and do not specify a json tag for it.

  1. type UserInfo struct {
  2. FirstName string `json:"firstName"`
  3. LastName string `json:"lastName"`
  4. Email string `json:"email"`
  5. }
  6. type SecretUser struct {
  7. UserInfo
  8. Password string `json:"password"`
  9. }
  10. func main() {
  11. data := []byte(`{"firstName": "nice","lastName":"guy","email":"nice@guy.co.uk","password":"abc123"}`)
  12. var u SecretUser
  13. json.Unmarshal(data, &u)
  14. fmt.Println(u)
  15. }

Go Play Space example

huangapple
  • 本文由 发表于 2022年3月4日 19:07:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/71350549.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定