-
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
encoding/json: json.Number accepts quoted values by default #34472
Comments
Same behavior with |
I think such behavior is historical, at least in go1.12 it is still same. Maybe the documentation has to be more explicit. |
Thanks for checking. |
Some changes related to Without looking deeply into the issue, remember that |
I can't think of why this would need to exist unless it were intended to work this way. To force conformance to a specific type in JSON, you could use the type directly instead of I think this could be clarified in documentation but changing the behavior would cause previously-working code to break. |
@kentquirk being a string for raw JSON value is ok, being a quoted string is less ok. As you would not expect the following code to return valid integer: strconv.Atoi(`"123"`) JSON.org defines values as:
Which makes an explicit difference between double-quoted string and number. The documentation says:
I also think this issue in likely about clarifying documentation given the potential impact of behavior change. Though maybe it would make sense to revisit behavior for Go 2. |
I quickly checked the code and I have come to the following conclusions:
if v.Type() == numberType && (!fromQuoted || !isValidNumber(string(s))) {
return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item)
}
|
I feel like the entire point of If you have JSON coming from JS that you don't control, you may see numbers encoded as strings. Worse, you may see them sometimes encoded as strings and sometimes as floats or integers, even for the same field. Your options to consume that in a Go API are:
I would argue that the latter is preferable -- because if you knew for sure that it was it not a string, you could have simply unmarshaled it directly into an If you're going to insist that |
Additional purpose of |
I think that's a good idea but can you point me to any code that supports that? If you marshal an int64 to a string you may store a value that doesn't successfully convert to a JS |
I don't think this behaviour should change because I rely on it as I'm sure many other people do. |
@Gobd unless I'm missing something, this would be trivial to fix when upgrading to Go 1.14, if the change is done in that release. The Non-API breaking changes should be kept at a minimum for sure, but given that the program in question is relying on the opposite of what the documentation says, and it would have a very simple fix, I don't see why we should be conservative. Particularly when the new behavior would be more consistent. There's also the argument that
No - the purpose of If it has been used by some to accept strings and non-strings quickly, that's simply using an unintended and undocumented side effect, which I'm arguing against at the start of my comment. |
To support the idea that this was never an intended or documented use of |
The upgrade would be more complicated in case of non-object, e.g. |
What benefit does @breml's fix have over documenting & adding tests to show that it supports strings & non-strings? I think that would be prefered vs changing current behaviour for what seems like no benefit. |
@Gobd the benefit is consistency, and actually following what has been documented since the beginning, including the purpose of the
Please read my longer comment above; I mention this specific use case. For example, here's a simple piece of code to accept both a string and a non-string for integer values (not using https://play.golang.org/p/bQBzvSvMv1e It requires ten more lines of code, but I think that's completely acceptable when your restriction is that you need to accept different kinds of JSON at once. And as said before, |
This behavior has been supporting quoted numbers since before I will also note that the specification behavior in the proto3 JSON mapping is to always quote So, it remains, the only way to guarantee full |
This change just broke the |
@mvrhov there has been no change yet. If there was, this issue would not be open with the @puellanivis it's indeed a tough choice. If we can't come to an agreement on changing it (which seems to be the case), then it's probably too late or painful to change it. I can have a look at a documentation change for 1.15, to at least have the documentation reflect the internal behavior that too many people have been relying on already. |
@mvdan A documentation change would not be enough. If we decide to raise the status of the current behavior to "fully supported", then we need to add test cases for this as well.
In regards to the go1 compat guarantee I do not agree with @puellanivis. I do not think, that this fix would be a violation, because this behavior is nowhere documented or specified. If we would treat this as a violation, we would end up in a situation, where we can never fix a bug in Go or the stdlib, because someone could potentially rely on the buggy behavior and it would break their code. |
Additionally, I would like to mention, that the documentation of
In the JSON specification, a number literal is defined as (link):
So the |
I am not arguing that just because someone might depend upon a buggy behavior, that bugs cannot be fixed. I am saying that changing unspecified behavior has to be done intelligently, and with respect to the users that might (accidentally) be relying upon that unspecified behavior. Even if we “fix” all of this, or introduce a And now after reading the two main standards ECMA-404, and RFC 8259, I don’t even think a change is necessary. The ECMA-404 standard specifically says:
And RFC 8259 also only defines only a grammar, not semantics. So, even with |
@puellanivis I am not sure, if I get your point in your last comment. The documentation of Of course the |
Regardless of what the documentation says, it has, since before go1.0, accepted string-quoted numeric values as well. The documentation and the implementation are in disagreement. The solution is to either fix the code, or fix the documentation. Because the JSON standard does not dictate semantics, there is no ground to stand on to say that we cannot have Nothing breaks if we fix the documentation, it is a strict superset of functionality. However, many things will break if we force the code to fit the documentation. |
To put it a different way: we can consider this an implementation bug (“ @puellanivis's point, as I understand it, is that the choice between those interpretations should be informed by existing usage. |
Yes, that is way more clearly what I wanted to say. Though, I wouldn’t say that I am firmly against changing the code to fit the documentation, but it should at least be carefully measured about what the effect either decision would lead to. |
Can't @breml 's suggestion be implemented the opposite way? Like, instead of a |
Such a change would still require a change of documentation to document the current behavior, and the new “strictlyNumeric” functionality. |
What @puellanivis said. Adding a new option is not a good solution; if anything, the bar for new json options is pretty high at this point. Personally, I've started to give up trying to fix the historical design issues with Whether or not the documentation should be updated is up to personal preference, I guess. I would personally not document these implementation quirks that were never meant to be. |
so this broke... that was fun |
@darnmason: Nothing has changed on this issue in 2 years. Are you suggesting that something changed in the |
It seems the documentation is still misleading. |
@dsnet I was a bit late to the party and updated an old project from go 1.13 to 1.16 Turns out my code was relying on the "feature" of json.Number being able to decode both number literals and quoted numbers |
@darnmason, I'm not sure how that matters since behavior related to this issue has not changed since at least |
ah so it hasn't actually changed. Sorry for the confusion, my bad. |
I'm curious how the ",string" approach would have helped here. With the current implementation of the string tag, the field must be quoted. This doesn't solve the common problem of a JS client using both quoted and unquoted formats. |
yes please, this is should be a sane default which field struct field? |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I've decoded a JSON value of
"123"
intojson.Number
.https://play.golang.org/p/9Nwjn3rBFxI
What did you expect to see?
I've expected to see an error.
What did you see instead?
I've seen a successful result and an int64 value of
123
accessible with.Int64()
.I could not find any documentation that
json.Number
accepts quoted string values by default and was expecting the opposite (as per "being precise" motivation expressed in #22463 (comment)).Not sure if this is a documentation or implementation issue.
The text was updated successfully, but these errors were encountered: