英文:
How do I omit a struct field *only* when marshalling, but keep it when unmarshalling?
问题
我有一个包含密码字段的User结构体。当我通过POST的JSON创建用户(或使用新密码更新用户)时,我希望将密码字段接受/解组到我的对象中,但是每当我返回一个用户时,我希望省略密码字段。以下是我目前能想到的最好的解决方案。它可以工作,但需要在我想要消除的字段名称周围进行大量重复(如果我添加一个像FirstName
这样的新字段,我必须在3个不同的位置添加它)。
在仍然遵守结构体上的json
标签的情况下,我该如何更好地实现这一点?
func main() {
origJson := []byte(`{"id":"1","username":"Chad","pwd":"sillypants"}`)
fmt.Println("Original: " + string(origJson))
var unmarshalled User
json.Unmarshal(origJson, &unmarshalled)
fmt.Printf("Unmarshalled: %+v\n", unmarshalled)
marshalled, _ := json.Marshal(unmarshalled)
fmt.Println("ReMarshalled: " + string(marshalled))
}
type User struct {
Id string `json:"id"`
Username string `json:"username"`
Password string `json:"pwd"`
}
type SafeUser struct {
Id string `json:"id"`
Username string `json:"username"`
}
func (u User) MarshalJSON() ([]byte, error) {
safeUser := SafeUser{
Id : u.Id,
Username: u.Username,
}
return json.Marshal(safeUser)
}
在Go Playground上尝试一下。
英文:
I have a User struct with a password field. When I'm creating a user (or udpating with a new password) via POSTed JSON, I want to accept/unmarshal the password field into my object, but whenever I return a user, I want to omit the password field. Below is the best I've been able to come up with so far. It works, but it requires a lot of duplication around the field names that I'd like to eliminate (right now, if I add a new field like FirstName
, I have to add that in 3 separate places).
How do I do this better while still honoring the json
tags on the struct?
func main() {
origJson := []byte(`{"id":"1","username":"Chad","pwd":"sillypants"}`)
fmt.Println("Original: " + string(origJson))
var unmarshalled User
json.Unmarshal(origJson, &unmarshalled)
fmt.Printf("Unmarshalled: %+v\n", unmarshalled)
marshalled, _ := json.Marshal(unmarshalled)
fmt.Println("ReMarshalled: " + string(marshalled))
}
type User struct {
Id string `json:"id"`
Username string `json:"username"`
Password string `json:"pwd"`
}
type SafeUser struct {
Id string `json:"id"`
Username string `json:"username"`
}
func (u User) MarshalJSON() ([]byte, error) {
safeUser := SafeUser{
Id : u.Id,
Username: u.Username,
}
return json.Marshal(safeUser)
}
Try it on the Go Playground
答案1
得分: 6
利用嵌入结构体的特性。定义一个User结构体,并将其嵌入到UnsafeUser结构体中,UnsafeUser结构体添加了password字段(以及其他任何字段,比如支付信息)。
type User struct {
Id string `json:"id"`
Username string `json:"username"`
}
type UnsafeUser struct {
User
Password string `json:"pwd"`
}
(最好默认情况下保持安全,并声明哪些是不安全的,就像Go的unsafe包一样。)
然后,你可以在不需要知道和复制所有字段的情况下从UnsafeUser中提取User。
func (uu UnsafeUser) MarshalJSON() ([]byte, error) {
return json.Marshal(uu.User)
}
$ go run ~/tmp/test.go
Original: {"id":"1","username":"Chad","pwd":"sillypants"}
Unmarshalled: {User:{Id:1 Username:Chad} Password:sillypants}
ReMarshalled: {"id":"1","username":"Chad"}
注意,你可以看到在解组UnsafeUser时嵌入的User结构体。
英文:
Take advantage of embedded structs. Define a User, and embed that in an UnsafeUser which adds the password field (and anything else, like payment info).
type User struct {
Id string `json:"id"`
Username string `json:"username"`
}
type UnsafeUser struct {
User
Password string `json:"pwd"`
}
(It's better to make things safe by default and declare what is unsafe, like Go's unsafe pacakge.)
Then you can extract the User from within the UnsafeUser without having to know and copy all the fields.
func (uu UnsafeUser) MarshalJSON() ([]byte, error) {
return json.Marshal(uu.User)
}
$ go run ~/tmp/test.go
Original: {"id":"1","username":"Chad","pwd":"sillypants"}
Unmarshalled: {User:{Id:1 Username:Chad} Password:sillypants}
ReMarshalled: {"id":"1","username":"Chad"}
Note how you can see the User struct embedded within the unmarshalled UnsafeUser.
答案2
得分: 5
我遇到了同样的问题,但是我找到了这篇文章。
这个想法是使用嵌入和匿名结构体来覆盖字段。
func (u User) MarshalJSON() ([]byte, error) {
type Alias User
safeUser := struct {
Password string `json:"pwd,omitempty"`
Alias
}{
// Leave out the password so that it is empty
Alias: Alias(u),
}
return json.Marshal(safeUser)
}
Alias 帮助防止在编组时出现无限循环。
请注意,为了使覆盖生效,你必须保持相同的 JSON 字段名称。
英文:
I had the same issue but came across this article.
The idea is to use embedding and an anonymous struct to override fields.
func (u User) MarshalJSON() ([]byte, error) {
type Alias User
safeUser := struct {
Password string `json:"pwd,omitempty"`
Alias
}{
// Leave out the password so that it is empty
Alias: Alias(u),
}
return json.Marshal(safeUser)
}
The Alias helps prevent an infinite loop while marshalling.
Please note that you have to maintain the same JSON field name for the override to work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论