I am attempting to define a custom JSON marshaler to display some time information in specific formats. Ideally, I'd like to have a struct that stores created/modified values and then embed them into structs that need to keep track of that information. In addition, I want to define a custom date format in the JSON marshaler to use from a client-side application.
I currently have two structs
type Timestamp struct {
Created time.Time
Modified time.Time
}
type Company struct {
Id string
Name string
Timestamp
}
I want to embed the Timestamp struct into objects that will need to record when items are updated/created. Nothing insane there.
My issues comes when I define
func (t Timestamp) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
CreatedFormatted string
}{
CreatedFormatted: t.Created.Format("Monday Jan _2 15:04:05 2006"),
})
}
When I go to marshal Company
, I only see the json for the Timestamp but nothing for the Company. I would have thought that the contents of the Company struct and the Timestamp struct would have been displayed. Am I doing something wrong here?
When a type embedded in a struct provides a method, that method becomes a part of the embedding struct. Since Company
embeds Timestamp
, Timestamp
's MarshalJSON
is available for Company
as well. When json is looking to marshal a Company
it sees that it has a MarshalJSON
method and calls it — and the method it finds only marshals the timestamp field. The default behavior of structs (to marshal each field into its own key in a JSON object) is overridden.
What you can do:
Timestamp
a regular field (even if you declare it as Timestamp Timestamp
). Then Company
won't inherit its methods and JSON will work as expected (but other parts of your code that expect embedding might change). Or:Company
its own MarshalJSON
method that marshalls all of the fields including the timestamp. You could do this byCompany
but without the embedding, and marshalling that.fmt.Sprintf({"key1":%s,"key2":%s,...}
, m1, m2, ...)
yourself.By embedding Timestamp
in Company
you not only shared member variables, but also the methods. This means you provided Company.MarshalJSON
method, which is then used by json
package for marshalling the whole structure. In order to see all the fields you would need to implement an explicit marshaler for Company
structure as well.
If you only want to format the timestamp in a specific way, the other solution would be to provide your own time.Time
and providing JSON marshaller there.
For example:
type AccessTime time.Time
func (t AccessTime) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Time(t).Format("Monday Jan _2 15:04:05 2006"))
}
type Timestamp struct {
Created AccessTime
Modified AccessTime
}
https://play.golang.org/p/PhZXPauSyz
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With