Repository navigation
x.json2: reject string-to-number type casting during decoding - #26220
Conversation
Honor the JSON specification which requires numeric values to be unquoted.
This fix lets `json.decode[int]('"100"')` correctly return a `JsonDecodeError` with message `"Expected number,
but got string"`, while unquoted numbers like `json.decode[int]('100')` continue to work as expected.
|
@Larsimusrex , @dy-tea what do you think? |
|
#23424 originally requested this feature. I don't think it is really a problem because a decoder that "does more than it should" doesn't create incompatible json files. It just increases compatibility with other poorly written encoders. Another example would be surrogate decoding which is non-standart but if removed would break compatibility with pythons json encoder. Also the json is only defines the syntax, not which datatypes should/shouldn't be allowed. |
|
What do you all think of @JalonSolov's idea, of adding a |
|
I think having this as an option is good but agree it doesn't need to be the default. |
Implementation: - `DecodeParams` struct with `strict` field - `decode2` function accepting params - Default mode: accepts quoted strings as numbers (for compatibility) - Strict mode: rejects quoted strings as numbers (JSON spec compliance) Tests: - Additional tests for both modes
|
Alright, good feedback guys. I've added a strict mode flag for JSON decoding with two modes:
Usage looks like this: import x.json2 as json
// Default mode - accepts quoted strings as numbers
value := json.decode[int]('"123"')! // returns 123
arr := json.decode[[]int]('["1", 2, "3"]')! // returns [1, 2, 3]
// Strict mode - rejects quoted strings as numbers
value := json.decode2[int]('123', strict: true)! // returns 123
json.decode2[int]('"123"', strict: true) or {
// Error: "Expected number, but got string"
} |
|
Hmmm.... May I suggest that the strict flag not be included in the function parameters? A public function to create a decoder with configuration would be nice, more or less like how it works in the encoder. |
|
@spytheman Do you prefer strict to be the default, or the other way around? |
|
@enghitalo I agree on all your points. For the question what should be the default, I think a tolerant parsing is the better choice and have the strict one as opt-in. It's pragmatic and follows the Robustness principle also known as Postel's law. This pattern is also seen in browsers and chooses practicality over pedantry. |
|
@enghitalo I also prefer the lenient mode (the one that is present right now) to be the default. I do not see a reason for the strict mode to be the default what so ever - it will break the backwards compatibility, and will make the overall system more brittle, since the decoder will be normally used to parse data coming from external sources. |
Add DecoderOptions and public Decoder struct to allow configurable JSON decoding. By default, the decoder accepts quoted strings as numbers for compatibility with real-world APIs (Postel's Law). Strict mode can be enabled for JSON spec compliance.
|
@fleximus please change it to: pub fn decode[T](val string, params DecoderOptions) !T {No deprecations are needed. Old code will still be able to call it just with: res := decode[Type]('....')!while new code can also do: res := decode[Type]('....', strict: true)! |
|
That will also remove the need for the |
Replace the Decoder struct and `new_decoder()` function with a single `decode()` function that accepts optional DecoderOptions parameter. This provides a cleaner API while maintaining backward compatibility: - Old: `json.decode[Type](str)!` - New: `json.decode[Type](str, strict: true)!` The `@[params]` attribute on `DecoderOptions` allows omitting the second argument when default (lenient) behavior is desired.
Honor the JSON specification which requires numeric values to be unquoted.
This fix lets
json.decode[int]('"100"')correctly return aJsonDecodeErrorwith message"Expected number, but got string", while unquoted numbers likejson.decode[int]('100')continue to work as expected.Fixes #26082