-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Behavior of JSONObject constructor trimming 0-led integers and converting them to int type instead of String type #826
Comments
@parker-mar Thanks for bringing this up and for coding up the comparison of behavior, that is really helpful. Do you think the behavior should be reverted, i.e. retain the leading zeros and interpret the value as a string? |
This library has never done unexpected conversions with the exception of unquoted strings. Given the following sample json document: {
"string1" : "000123",
"string2" : "abc123",
"string3" : abc123,
"number1" : 123,
"number2" : 000123
} Before the change, I believe all of those values would have been stored internally in JSONObject as strings except After the change I would expect that both If after the change, |
As a followup, a json document like in the example provided by @parker-mar ( My real answer would be to have whatever is generating |
In testing last night, it seemed to me that |
Hi, thanks for the prompt responses!
Indeed it was not a great example, unfortunately it happened in our case that we relied on this pre-existing behavior for JSON exchange of 8-digit person IDs, which caused runtime failures for the consumer that used The problem may recur in the future if Java 15 text blocks become more popular (e.g. https://stackoverflow.com/a/61432423): String personId = "00701234";
JSONObject jsonPayload = new JSONObject("""
{
"name": "Parker",
"id": %s
}""".formatted(personId));
jsonPayload.getString("id"); // Throws exception
I understand that the parser is designed to accept as input more than the generator #465 (comment), but it wasn't entirely clear to me if the purpose of trimming the leading 0s was to handle octal parsing. If we're looking for reasonable defaults "past" the JSON spec, I think retaining the leading 0s and interpreting the value as a string is a safer/more explicit transformation than trimming for octal values. I also think it's a more common use case, besides that it would maintain the previous behavior.
I think you may have meant to tag #783. |
This is a very bad way to generate a JSONObject. This is NOT recommended for the same reason that it's not recommended to build SQL queries using string building. It's very easy to break the expected syntax and have things break, worst case become a security issue. If using this library, the recommended way to build this object would be: String personId = "00701234";
JSONObject jsonPayload = new JSONObject()
.put("name", "Parker")
.put("id", personId); Any type of payload that needs to be exchanged, even internally, that has very specific syntax rules should use the OOTB builders available. |
I disagree. These test cases were explicitly in the tests provided as part of the PR. I understood this to be an objective of the PR. |
Right. I also prefer the use of the builders so that we rely on the Java language type system to supply the correct value types, data payload or not. Still, I can imagine some without the same foresight may turn to using the JSONObject constructor because of the ease of reading code snippets beyond even the simplicity of the OOTB builders, e.g. Text Blocks, which is in a way a primary motivation of that feature:
|
@johnjaylward It's my bad, I missed this behavior change, should have been paying closer attention to the PRs. |
@parker-mar @johnjaylward @stleary I have tested that, if the value in JSON is a string, then the JSON object always retains a string value. If the user wants to get a number out of the string, then JSON Object helps by lifting the load of parsing string to number. If the value is parsable to a number, JSON object would do that and return. If the JSON value is without quotes, and is an intended number, then it is expected that the value will be a legitimate number. On such values, when get or opt long/int is called, if the number is valid, that gets returned and of course, without the leading zeros. If the value is intended to be a number, and is not a legitimate number, then JSON object returns 0 for them. I have tested these behaviours in the following code.
For the number fields, calling getString on them throws an exception. This is where probably we have a scope if improvement. JSON Object may store the original value, and getString would return the original value (it could be a legitimate number, a number with leading zeros, or a set of non-number characters). |
@rudrajyotib No worries, you did nothing wrong. It is my responsibility to provide the guardrails so that contributors don't accidentally break existing projects with a code change, so this is on me. |
This issue may have turned up in #852. Investigating... |
We are seeing this behavior, or at least related behavior, as well, but only after updating from 20231013 to 20240205. We extensively use the XML to JSON transformation offered by this library, and see the following change happening: Given an XML: ...
<datatypes>
<telephone>0123456789</telephone>
<amount>0.1230</amount>
<boolean>true</boolean>
</datatypes>
... and our code: JSONObject o = XML.toJSONObject(xml, keepStrings); Behavior in 20231023 with {"amount":0.123,"boolean":true,"telephone":"0123456789"} Behavior in 20240205 with {"amount":0.123,"boolean":true,"telephone":123456789} As phone numbers in our country (as in most of Europe I believe) start with a 0, it was very helpful that JSON-java understood that and treated strings with leading zeroes as a string instead of an integer. This has changed and for us, functionally, this is indeed regression as suggested before. We do not want the |
@bartlaarhoven Thanks for posting. This issue will be resolved in the next 48 hours. The new behavior will either be reverted, or changed to opt-in, depending on how the code looks. A new version will also be released. |
Hello there! I am curious about the new behavior introduced in 20231013 (ref #783), where the JSONObject constructor trims 0-led integers and converts them to int type instead of String type (which was the type in 20230618).
While I can understand the rationale behind trimming, the change in behavior could be problematic for things like IDs with leading 0s, which may have previously relied on the JSONObject constructor preserving the value as String type, only to have it converted to int, and thus failing a subsequent call to JSONObject
getString("id")
because of type mismatch.Comparing with other Java JSON libraries, org.json seems to behave in a way that's potentially unsafe as it transforms the input and therefore "hides" the error, versus the other libraries which take a safer approach by throwing an error on input (javax.json, Jackson) or treating the input as "pseudo"-json and letting the getter decide the type (Gson).
The text was updated successfully, but these errors were encountered: