How to correctly json.Unmarshal struct whose embedded structs define UnmarshalJSON

2,424 views
Skip to first unread message

Glen Huang

unread,
Dec 31, 2019, 5:21:07 AM12/31/19
to golang-nuts
I want to unmarshal a struct that contains embedded structs:

type Parent struct {
 
Child
 P
int
}


type
Child struct {
 
Grandchild
 C
int
}


type
Grandchild struct {
 G
int
}

The problem is that Grandchild defines its own UnmarshalJSON method, and that means Parent inherits it and breaks json.Unmarshal.

I wonder if it's possible to correctly unmarshal Parent without overriding UnmarshalJSON for every member in the embedding chain? It's correctly the only way I know that can fix the issue, but it's very cumbersome, and there are cases where I only have control over Parent, but not Child and Grandchild,

Thanks. 

Glen Huang

unread,
Dec 31, 2019, 6:19:39 AM12/31/19
to golang-nuts
After thinking more about it, I start to feel that maybe using embedded structs is generally a bad idea with dealing with json? Is the correct solution here to use explicit fields?

BTW, happy New Year everyone.

Space A.

unread,
Jan 1, 2020, 3:58:32 AM1/1/20
to golang-nuts
1. I think it's not correct to use terms "parent" and "child", as Go is not an OOP language.
2. Please note that what you call a Child is actually a Parent, and vice versa. This puts a lot of confusion.
3. Embedding struct will get methods of embedded (depending on whether they've been defined for value or pointer receivers and so on), so if I get your question right, then when you "inherit" these methods and you don't want this to happen, either not embed (put in a field instead), or override this method, or make this method be more universal for different cases.

Ben Bullock

unread,
Jan 1, 2020, 8:19:23 PM1/1/20
to golang-nuts


On Tuesday, 31 December 2019 19:21:07 UTC+9, Glen Huang wrote:
I want to unmarshal a struct that contains embedded structs:

type Parent struct {
 
Child
 P
int
}


type
Child struct {
 
Grandchild
 C
int
}


type
Grandchild struct {
 G
int
}

The problem is that Grandchild defines its own UnmarshalJSON method, and that means Parent inherits it and breaks json.Unmarshal.

The behaviour of encoding/json in your case seems odd to me.


Is there a good reason why it does this?

Glen Huang

unread,
Jan 2, 2020, 1:01:15 AM1/2/20
to golang-nuts
@Ben

My real world use case is that I have these types that dealing with user signing up/loging in

type LogIn struct {
  Name string
  Password string
}

type SignUp struct {
  Name string
  Password string
  Gender string
}
  

I was hoping that I cloud embed LogIn inside SignUp, to eliminate duplicate fields. LogIn has a UnmarshalJSON that, for example, decrypts password after parsing it, which ideally could be picked up by SignUp automatically, without me having to wrap another UnmarshalJSON for SignUp. Is achieving this shortcut through embedding possible?

@Space

> then when you "inherit" these methods and you don't want this to happe

Given the case above, I'm wondering if embedding + not overriding method is possible?

Ben Bullock

unread,
Jan 2, 2020, 1:51:26 AM1/2/20
to golang-nuts


On Thursday, 2 January 2020 15:01:15 UTC+9, Glen Huang wrote:
@Ben

My real world use case is that I have these types that dealing with user signing up/loging in

type LogIn struct {
  Name string
  Password string
}

type SignUp struct {
  Name string
  Password string
  Gender string
}
  

I was hoping that I cloud embed LogIn inside SignUp, to eliminate duplicate fields. LogIn has a UnmarshalJSON that, for example, decrypts password after parsing it, which ideally could be picked up by SignUp automatically, without me having to wrap another UnmarshalJSON for SignUp.

In my opinion that's a misuse of UnmarshalJSON. The decrypting should be separate from the unmarshalling, or even better just use the built in unmarshalling and decrypt it somewhere else.
 
Is achieving this shortcut through embedding possible?

Sorry but I don't know. I tried working on your problem out of interest, and I posted a response because I thought the behaviour displayed was unexpected.

Reply all
Reply to author
Forward
0 new messages