Introduction
In this blog post, we will discuss an interesting case in Golang where using a custom UnmarshalJSON method on a struct with both inner and outer fields results in only the inner fields being unmarshaled. We will look into why this occurs and suggest two alternative solutions to overcome this issue. Let's start by understanding the problem.
The Problem
Consider the following Go code with a struct named Person that has inner and outer fields:
type Name struct {
First string `json:"first"`
Last string `json:"last"`
}
type Person struct {
Name
Age int `json:"age"`
}
Now, we want to implement a custom UnmarshalJSON method for the Person struct:
func (p *Person) UnmarshalJSON(data []byte) error {
type alias Person
aux := struct {
*alias
Age int `json:"age"`
}{
alias: (*alias)(p),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
p.Age = aux.Age
return nil
}
The expected behavior is that the custom UnmarshalJSON method should unmarshal both inner (Name) and outer (Age) fields. However, it turns out that only the inner fields are unmarshaled, and the outer field (Age) is ignored.
Why This Happens
The issue arises due to the use of the embedded struct Name in the Person struct. When the custom UnmarshalJSON method is called, it tries to unmarshal the JSON data into the embedded struct first. The outer field (Age) is then shadowed by the inner field with the same name in the auxiliary struct, which causes it to be ignored during the unmarshaling process.
Alternatives
To overcome this issue, we have two alternative solutions:
- Refactor the struct to have no inner fields:
type Person struct {
FirstName string `json:"first"`
LastName string `json:"last"`
Age int `json:"age"`
}
By doing this, we avoid the issue of field shadowing and ensure all fields are unmarshaled correctly.
- Create a separate
UnmarshalJSONmethod for the inner struct:
func (n *Name) UnmarshalJSON(data []byte) error {
type alias Name
aux := &struct {
*alias
}{
alias: (*alias)(n),
}
if err := json.Unmarshal(data, aux); err != nil {
return err
}
return nil
}
By creating a separate UnmarshalJSON method for the inner struct (Name), we ensure that the JSON data is correctly unmarshaled for both the inner and outer fields.
Conclusion
In this blog post, we explored the peculiar behavior of Golang's custom UnmarshalJSON method when used with a struct containing both inner and outer fields. We discovered that only the inner fields are unmarshaled, and the outer fields are ignored due to field shadowing. To resolve this issue, we presented two alternative solutions - either refactor the struct to have no inner fields or create a separate UnmarshalJSON method for the inner struct.
Related Posts
Lessons in cybersecurity, Part I
Here's a little story from the trenches, from far far away when I was a kiddo learning my way through webservers, PHP and vulnerable (pirated) bulletin boards software. ๐๐ป Intro A long time ago around 200* something, I was really interested in game hacking related topics and somehow I got in...
The Power Of Choosing Optimism
"The happiness of your life depends upon the quality of your thoughts." - Marcus Aurelius My first memories of childhood are grey, not in the cool, noir style of 1920s movies, but in the bleak, post-communist greyness of 1990s Romania. I was surrounded by people who had hoped for freedom for so
Unraveling the Mystery of Ignored Files with git check-ignore
In the world of version control, Git has become an indispensable tool for developers. One of its key features is the ability to selectively ignore certain files or directories with the help of the .gitignore file. This can be a real lifesaver when you need to exclude files that don't belong in your repository, like build artifacts, logs, or user-specific settings. However, sometimes it can be challenging to figure out why a particular file is being ignored. That's where the git check-ignore command comes in handy! In this blog post, we'll explore this powerful yet underutilized Git command and how it can help you understand your .gitignore configuration....
Comments
Comments from this blog and Bluesky
No comments yet. Be the first to comment!