-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: encoding/json, encoding/xml: support zero values of structs with omitempty #11939
Comments
CL https://golang.org/cl/13914 mentions this issue. |
CL https://golang.org/cl/13977 mentions this issue. |
In the CLs @rsc said,
I see what he's getting at. CL 13977, which implements the However, I still feel strongly about I use the JSON encoding in Go a lot, as my work is mostly writing services that communicate with other services, in multiple languages, over HTTP. The fact that structs don't obey I think it should be considered a bug that Go does not support |
This proposal is marked as unplanned, yet the related bug report #10648 is marked as go1.7. |
To my knowledge, it is not being worked on. Honestly this seems fairly low On Sun, Mar 27, 2016 at 12:22 PM Jérôme Andrieux notifications@github.com
|
OK. This is more of a convenience than a priority indeed. It can be a pain point when dealing with libs that don't support "embedded structs" as pointer though. |
I wonder if a low-impact alternative to the It's not a perfect solution, since one can't add methods to types defined in another package, but this can be worked around to a degree. Taking the type MyTime struct {
time.Time
}
// Implement the Marshaler interface
func (mt MyTime) MarshalJSON() ([]byte, error) {
res, err := json.Marshal(mt.Time)
if err == nil && mt.IsZero() {
return res, json.CanOmit // Exclude zero value from fields with `omitempty`
}
return res, err
} I haven't looked into implementation, but on the surface it would seem like a low-overhead solution, assuming the only work would be to check if an error returned equals Using errors as a flag is not without precedent in the standard library, e.g. |
@Perelandric I mentioned a possible sentinel error value in https://golang.org/cl/13914 but I didn't get feedback on the idea or an opportunity to implement it before the Go 1.7 freeze. After Russ's comments on my original CL (and showing the unexpected difficulty in implementing this) I think that's the better way to go. |
CL https://golang.org/cl/23088 mentions this issue. |
While it's clear that we can do this, it's not clear that we want to. I'd like to see a formal proposal document that weighs the advantages and drawbacks of this feature addition. In particular, I am concerned about compatibility and maintenance burden. |
thanks Andrew. I worked on this a little bit at GopherCon. I will look into putting together a formal proposal. |
@joeshaw we ran into this issue at my place of work and I'm eagerly awaiting your proposal. Feel free to contact me if you would like any help. Email is on my profile. |
@joeshaw Is the proposal you're considering based on the sentinel object idea, or are you considering a different approach? Do you think you'll have time for this before the next release? |
@Perelandric Yes, I think the sentinel object idea is the most straightforward way to go. Other options include:
I don't think I will be able to do this (proposal + implementation) before Go 1.8. If someone else wants to take it on for 1.8, I will gladly pass along my knowledge and partial implementation. |
Thanks @joeshaw. I created an implementation using the sentinel error for the The After I make a little more progress, I'll post a link to a branch in case you, @albrow or anyone else wishes to review and contribute. If you have any additional thoughts or info in the meantime, please let me know. Thank you! |
Change of heart on this. If there's resistance to adding to packages, then this won't fly. Maybe someone else wishes to advocate for this. |
Mentioned in one of the duplicate issues was the idea to let MarshalJSON return (nil, nil) to skip the field. Borrowing your earlier example:
In Go 1.7, returning nil is not a valid implementation for MarshalJSON and leads to "unexpected end of JSON input" errors. This approach doesn't require any visible change to the encoding package (not even adding an error value). For what it's worth, I just intuitively wrote a MarshalJSON method like that, expecting a field to be omitted from the JSON output. |
@pschultz That approach seems reasonable to me, but it can't be used with The reason you get that error is because the JSON encoder checks for the validity of the JSON coming out of The benefit of the error value is that it could fit in with the existing |
@pschultz: A I don't know if having |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as duplicate.
This comment was marked as duplicate.
There are some slow-moving plans for encoding/json/v2. |
Hi all, we kicked off a discussion for a possible "encoding/json/v2" package that addresses the spirit of this proposal at least for JSON. See the "omitzero" struct tag option under the "Struct tag options" section. |
My team inherited maintenance duties for a Go application, and we just had to fix a bug caused by the legacy code trying to use the As a JS developer, I can tell you that sending an empty object value ( |
As a workaround, I've had good luck using https://github.com/clarketm/json (which is a re-implementation of import (
"encoding/json"
jsonx "github.com/clarketm/json"
)
func (s OuterStruct) MarshalJSON() ([]byte, error) {
// Use a type Alias to prevent Marshal recursion
type TmpStruct OuterStruct
// jsonx omits empty structs
return jsonx.Marshal(TmpStruct(s))
} |
The |
If this is being closed in favor of #45669, is there a separate issue already going that I could follow to make applying |
That sounds like a reasonable `govet` enhancement.
|
Thanks @dsymonds , do you know where it would be appropriate to make that request? I can't tell if ETA: I found https://pkg.go.dev/golang.org/x/tools@v0.25.0/go/analysis/passes/structtag which appears to implement the "analysis" suite checker for struct tags specifically. That info page doesn't link to an issue tracker, as far as I can tell. ETA again: apparently I commented on #51261 previously, which is a very similar proposal but currently only scoped to time.Time values, rather than any zero-value struct. I don't know whether the maintainers would prefer a second issue, or whether it would be better to broaden the scope of the existing one. (Personally I prefer the latter, but it's not my project, so...) |
@thw0rted: This issue tracker is probably fine. There's plenty of other issues for govet already here. |
A new vet check should be opened in this issue tracker as a proposal. See https://go.dev/s/proposal. Thanks. |
@ianlancetaylor it looks like the candidate implementation for #51261 actually covers this case, even though the title of that proposal still says it's only about |
Thanks, I agree that the existing proposal is sufficient here. |
Support zero values of structs with omitempty in encoding/json and encoding/xml.
This bites people a lot, especially with
time.Time
. Open bugs include #4357 (which has many dups) and #10648. There may be others.Proposal
Check for zero struct values by adding an additional case to the
isEmptyValue
function:This will solve the vast majority of cases.
(Optional) Introduce a new
encoding.IsZeroer
interface, and use this to check for emptiness:Update: I am dropping this part of the proposal, see below.
Visit this playground link and note that the unmarshaled
time.Time
value does not have anil
Location
field. This prevents the reflection-based emptiness check from working.IsZero()
already exists ontime.Time
, has the correct semantics, and has been adopted as a convention by Go code outside the standard library.An additional check can be added to the
isEmptyValue()
functions before checking the value'sKind
:Compatibility
The
encoding.IsZeroer
interface could introduce issues with existing non-struct types that may have implementedIsZero()
without consideration ofomitempty
. If this is undesirable, theencoding.IsZeroer
interface check could be moved only within the struct case:Otherwise, this change is backward-compatible with existing valid uses of
omitempty
. Users who have appliedomitempty
to struct fields incorrectly will get their originally intended behavior for free.Implementation
I (@joeshaw) have implemented and tested this change locally, and will send the CL when the Go 1.6 tree opens.
The text was updated successfully, but these errors were encountered: