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

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

Custom unmarshalling from flat json to nested struct

问题

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

type SecretUser struct {
    UserInfo `json:"userInfo"`
    Password string `json:"password"`
}

type UserInfo struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Email     string `json:"email"`
}

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

{
    "firstName": "nice",
    "lastName": "guy",
    "email": "nice@guy.co.uk",
    "password": "abc123"
}

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

func (u *User) UnmarshalJSON(data []byte) error {
    var objmap map[string]*json.RawMessage
    var password string
    var err error

    err = json.Unmarshal(data, &objmap)
    if err != nil {
        return err
    }

    if err := json.Unmarshal(data, &u.UserInfo); err != nil {
        return err
    }
    
    err = json.Unmarshal(*objmap["password"], &password)
    if err != nil {
        return err
    }

    u.Password = password
    return nil
}

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

英文:

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

type SecretUser struct {
	UserInfo `json:"userInfo"`
	Password string `json:"password"`
}

type UserInfo struct {
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
	Email     string `json:"email"`
}

And I receive a JSON in this form:

{
	"firstName": "nice",
	"lastName":"guy",
	"email":"nice@guy.co.uk",
	"password":"abc123"
}

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

func (u *User) UnmarshalJSON(data []byte) error {
	var objmap map[string]*json.RawMessage
	var password string
	var err error

	err = json.Unmarshal(data, &objmap)
	if err != nil {
		return err
	}

	if err := json.Unmarshal(data, &u.UserInfo); err != nil {
		return err
	}
	
	err = json.Unmarshal(*objmap["password"], &password)
	if err != nil {
		return err
	}

	u.Password = password
	return nil
}

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标签。

type UserInfo struct {
    FirstName string `json:"firstName"`
    LastName  string `json:"lastName"`
    Email     string `json:"email"`
}

type SecretUser struct {
    UserInfo
    Password string `json:"password"`
}

func main() {
    data := []byte(`{"firstName": "nice","lastName":"guy","email":"nice@guy.co.uk","password":"abc123"}`)
    var u SecretUser
    json.Unmarshal(data, &u)
    fmt.Println(u)
}

Go Play Space 示例

英文:

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

type UserInfo struct {
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
	Email     string `json:"email"`
}

type SecretUser struct {
	UserInfo
	Password string `json:"password"`
}

func main() {
	data := []byte(`{"firstName": "nice","lastName":"guy","email":"nice@guy.co.uk","password":"abc123"}`)
	var u SecretUser
	json.Unmarshal(data, &u)
	fmt.Println(u)
}

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:

确定