-
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: reject unknown fields in Decoder #15314
Comments
Could we add a mechanism to the json package that allows a struct to declare that it should have strict or non-strict handling, independent of how the decoder is configured? This could be an interface, or a pair of zero-size types (or a bool type) that could be embedded -- in much the same way that the xml package provides configurability -- or perhaps a json struct tag that could be recognized on any padding field. There are cases where it's desirable for some json objects in a "document" to be treated strictly, whereas others in the same document should be non-strict (yet still warrant use of a struct instead of a map). Allowing an "overflow" map field would make it easier to express this (if you include such a map field, and turn on strict handling, the containing struct would be non-strict). |
This is a duplicate of #14750. Continuing @extemporalgenome's thought, I wonder if the strictness should always be in the tag instead of a new method. Per-struct is difficult but per-field is fine. You could imagine |
Ah, thanks very much. OK, then UseStrictFields is definitely a bad name. :-) We could certainly solve Dave's problem but I wonder if we should do something a bit more generic. In the XML decoder there is a ",any" tag that you can use to say "unexpected things go here". I wonder if JSON should allow a map[K]V (K=string, V=interface{} would be common but not strictly required) to have a tag It might be too late for Go 1.7 to work all this out. |
The "overflow" map discussed by @extemporalgenome and @rsc has been requested a few times. In fact, #6213 already exists for such a proposal. (The confusing name "inline" for the feature makes it hard to discover.) Perhaps this bug should supersede #6213. |
I like the overflow map as a solution to the extra keys problem. I think the dual of this issue is also important: sometimes you want to know that a key was missing from the JSON object. (In the case of a misspelling as in @okdave's motivation, you could detect either the missing key or the extra key.) Adding a way to error on missing JSON keys is tracked by #6901. I believe these should be considered at the same time. |
An overflow map would work for this purpose. One downside to adding that as a struct field would be that for deeply nested structures, you'd need to add the field to multiple structs and do a lot of manual bookkeeping after unmarshalling. One big advantage is no (terribly named) new method on Decoder and that it works with Unmarshal too. Would that same map be used to add additional keys during Marshal? Or ignored there? |
@okdave users would likely expect any |
Yup, I agree. @rsc I wasn't aiming for 1.7, but I'm happy to jump on this if there's consensus on this approach. |
I need this as well. When parsing configs any unknown field is either a typo, or an old version, or something equally bad.
would work for me. |
On second thought, any sink will work poorly with nested structs. One would need to add the sink to all structs and then manually check all of them. Obviously error prone. |
I'm +1 on providing a way to do this.
The implementation is trivial - I can propose it if this proposal is agreed on. I see this as orthogonal to the UseStrictNames suggestion from #14750. |
This issue seems to be an exact duplicate of #6901. |
+1 for DisallowUnknownFields(). The interface is similar to the existing |
I have a patch that implements this feature. It is passing nearly all of the existing encoding/json unit tests except one test is failing. Wasn't sure how to get feedback on my patch? Do I submit it to gerrit even though it needs additional work? I've created a pull request from my fork against my fork so that the changes can be browsed: https://github.com/mspiegel/go/pull/1/files. The failing test is related to a key that is being "annihilated", that's the terminology in the source code when two fields in a struct have the same JSON name. |
If you have a change that's ready for people to provide feedback on, gerrit's the right place to have the discussion. If there's one thing you can't figure out, then just check the rest of the change is sane and send it out. You should add a comment to the change once you've mailed it to indicate what help you still need, and add "DO NOT SUBMIT" on the second line of the commit message to indicate that the CL is currently unworkable. Per @rsc do not submit means "something you do want people to see and review but that you know is not ready". Let me know if you need more info. |
CL https://golang.org/cl/27231 mentions this issue. |
Thanks for the initial feedback on gerrit it has been helpful. Can I convince a consensus to change the name of the new option from |
I prefer |
OK works for me. I'll move forward on the patch. |
What happens next? The patch is complete and submitted to gerrit https://golang.org/cl/27231. It's waiting further review. |
@mspiegel I see, thank you for the clarification! |
I like IMO, the two cases are closely related and I would like to see them both addressed at the same time. |
The values that are collected in the ",any" feature, what are their types?
Is it a map of string to sting? A map of string to interface? I was
hesitant to make that decision. Because I'm not sure what is the right
answer. And also I would prefer not to have that discussion derail the rest
of the feature. I really need JSON validation as soon as possible. I'm
surprised that others are not in the same boat.
In the current feature proposal, the error response will return a slice
with the unknown keys. The caller is free to do whatever they want with
those keys. This is 90% of the functionality of the ",any" proposal and it
doesn't make a design decision on the remaining 10% that is ambiguous.
…On Feb 1, 2017 1:46 PM, "Luke Scott" ***@***.***> wrote:
I like DisallowUnknownFields when you want to have strict validation. It
keeps the structs clean. However, I would also like to see a json:",any"
option for cases where you want to collect fields not defined in the
struct. In my case I have an object that has some well known fields, but I
also want to keep user-defined data that is not well known.
IMO, the two cases are closely related and I would like to see them both
addressed at the same time.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#15314 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAtnZX9RUyqaBZgj0tA_IWerpRYifOeks5rYNMXgaJpZM4IIA7_>
.
|
Given that Even if you could support other types such as What if |
There could be a special type
It would be nice if this was possible for |
We had several options how to implement that: * one plan and user provided json to specify number of units: we dont like this option * multiple plans and we hardcode number of units based on plan name which means we have to change broker code every time the plan changes : nah... * fork brokerAPI and modify the Catalog struct and do PR upstream: it's hard to extend this in a generic way by using json.RawMessage. The name of the field has to be known and speciefied as json unmarshaller option. So we would have to specify `json:"units,omitempty"` json unmarshaler option which is very compose specific. There is a go lang issue opened to fix that: golang/go#15314 * do not use upstream Catalog and implement our own struct. Not posible - we have to return the type specified in the brokerapi interface to implemet it: https://github.com/pivotal-cf/brokerapi/blob/0d62e62ec041b8ff39c0e304f437b4eabb4175fa/service_broker.go#L10 * extend external Catalog struct to include units field - not possible. same reason as above I had to implement the sixth option. Now we have a new struct that partialy copies upstream catalog structure but holds only fields (IDs and Units ) that we care about. This together with upstream catalog is wrrapped into on struct and stored in main broker structure so all interface methods have access to it. There is also new catalog.Load method that replaces catalog.New. It has two unmarshalling passes to fill upstream catalog and our Units struct.
We had several options how to implement that: * one plan and user provided json to specify number of units: we dont like this option * multiple plans and we hardcode number of units based on plan name which means we have to change broker code every time the plan changes : nah... * fork brokerAPI and modify the Catalog struct and do PR upstream: it's hard to extend this in a generic way by using json.RawMessage. The name of the field has to be known and speciefied as json unmarshaller option. So we would have to specify `json:"units,omitempty"` json unmarshaler option which is very compose specific. There is a go lang issue opened to fix that: golang/go#15314 * do not use upstream Catalog and implement our own struct. Not posible - we have to return the type specified in the brokerapi interface to implemet it: https://github.com/pivotal-cf/brokerapi/blob/0d62e62ec041b8ff39c0e304f437b4eabb4175fa/service_broker.go#L10 * extend external Catalog struct to include units field - not possible. same reason as above I had to implement the sixth option. Now we have a new struct that partialy copies upstream catalog structure but holds only fields (IDs and Units ) that we care about. This together with upstream catalog is wrrapped into on struct and stored in main broker structure so all interface methods have access to it. There is also new catalog.Load method that replaces catalog.New. It has two unmarshalling passes to fill upstream catalog and our Units struct.
We had several options how to implement that: * one plan and user provided json to specify number of units: we don't like this option * multiple plans and we hardcode number of units based on plan name which means we have to change broker code every time the plan changes : nah... * fork brokerAPI and modify the Catalog struct and do PR upstream: it's hard to extend this in a generic way by using json.RawMessage. The name of the field has to be known and specified as json unmarshaller option. So we would have to specify `json:"units,omitempty"` json unmarshaler option which is very compose specific. There is a go lang issue opened to fix that: golang/go#15314 * do not use upstream Catalog and implement our own struct. Not possible - we have to return the type specified in the brokerapi interface to implement it: https://github.com/pivotal-cf/brokerapi/blob/0d62e62ec041b8ff39c0e304f437b4eabb4175fa/service_broker.go#L10 * extend external Catalog struct to include units field - not possible. Same reason as above I had to implement the sixth option. Now we have a new struct that partially copies upstream catalog structure but holds only fields (IDs and Units ) that we care about. This together with upstream catalog is wrrapped into one struct and stored in main broker structure so all interface methods have access to it. There is also new catalog.Load method that replaces catalog.New. It has two unmarshalling passes to fill upstream catalog and our Units struct.
Change https://golang.org/cl/74830 mentions this issue: |
Currently, json.Unmarshal (and json.Decoder.Decode) ignore fields in the incoming JSON which are absent in a target struct.
For example, the JSON
{ "A": true, "B": 123 }
will successfully unmarshal intostruct { A bool }
.This makes it difficult to do strict JSON parsing. One place this is an issue is in API creation, since you want to reject unknown fields on incoming JSON requests to allow safe introduction of new fields in the future (I've had this use case previously when working on a JSON REST API). It also can lead to typos leading to bugs in production: when a field is almost always the zero value in incoming JSON, you might not realise you're not even reading a misspelled field.
I propose that a new method is added to
Decoder
to turn on this stricter parsing, in much the same wayUseNumber
is used today. When in strict parsing mode, a key in the incoming JSON which cannot be applied to a struct will result in anMissingFieldError
error. LikeUnmarshalTypeError
, decoding would continue for the remaining incoming data.The text was updated successfully, but these errors were encountered: