From 2f8798665aeebd7c8bcbcea1e8121d89f1cf9660 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 21 Jun 2022 15:52:21 +0100 Subject: [PATCH 01/13] support option to enable trailing decimal point --- .../fasterxml/jackson/core/JsonParser.java | 6 +++ .../jackson/core/json/JsonReadFeature.java | 16 +++++++- .../core/json/ReaderBasedJsonParser.java | 8 +++- .../core/json/UTF8DataInputJsonParser.java | 4 +- .../core/json/UTF8StreamJsonParser.java | 4 +- .../json/async/NonBlockingJsonParser.java | 8 +++- .../read/NonStandardNumberParsingTest.java | 40 +++++++++++++++++++ 7 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java index 6fa8c43f5c..cdfc11f7fe 100644 --- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java @@ -188,6 +188,12 @@ public enum Feature { @Deprecated ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false), + /** + * @deprecated Use {@link com.fasterxml.jackson.core.json.JsonReadFeature#ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS} instead + */ + @Deprecated + ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS(false), + /** * Feature that allows parser to recognize set of * "Not-a-Number" (NaN) tokens as legal floating number diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java b/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java index 304b320a12..6b0037dd50 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java +++ b/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java @@ -113,7 +113,7 @@ public enum JsonReadFeature * (like: .123). If enabled, no exception is thrown, and the number * is parsed as though a leading 0 had been present. *

- * Since JSON specification does not allow leading decimal, + * Since JSON specification does not allow leading decimal points, * this is a non-standard feature, and as such disabled by default. * * @since 2.11 @@ -121,6 +121,20 @@ public enum JsonReadFeature @SuppressWarnings("deprecation") ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS), + /** + * Feature that determines whether parser will allow + * JSON decimal numbers to end with a decimal point + * (like: 123.). If enabled, no exception is thrown, and the number + * is parsed as though the trailing decimal point had not been present. + *

+ * Since JSON specification does not allow trailing decimal points, + * this is a non-standard feature, and as such disabled by default. + * + * @since 2.11 + */ + @SuppressWarnings("deprecation") + ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS), + /** * Feature that allows parser to recognize set of * "Not-a-Number" (NaN) tokens as legal floating number diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java index da788986c6..7bc80fd33b 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java @@ -1408,7 +1408,9 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg, } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); + if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); + } } } int expLen = 0; @@ -1585,7 +1587,9 @@ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOExcept } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); + if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); + } } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java index 3d2fd99777..886a545c81 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java @@ -1165,7 +1165,9 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c, } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); + if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); + } } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java index 5ad5502d63..5cbb2c7777 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java @@ -1638,7 +1638,9 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c, } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); + if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); + } } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java index 9c7e2adbd5..5f977ba235 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java @@ -1655,7 +1655,9 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce ch &= 0xFF; // but here we'll want to mask it to unsigned 8-bit // must be followed by sequence of ints, one minimum if (fractLen == 0) { - reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); + if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); + } } break; } @@ -1745,7 +1747,9 @@ protected JsonToken _finishFloatFraction() throws IOException // Ok, fraction done; what have we got next? // must be followed by sequence of ints, one minimum if (fractLen == 0) { - reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); + if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); + } } _fractLength = fractLen; _textBuffer.setCurrentLength(outPtr); diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java index 7cdd194909..996412a66f 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java @@ -8,6 +8,7 @@ public class NonStandardNumberParsingTest { private final JsonFactory JSON_F = JsonFactory.builder() .enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS) + .enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS) .build(); protected JsonFactory jsonFactory() { @@ -30,6 +31,22 @@ public void testLeadingDotInDecimal() throws Exception { } } + /** + * The format "NNN." (as opposed to "NNN") is not valid JSON, so this should fail + */ + public void testTrailingDotInDecimal() throws Exception { + for (int mode : ALL_MODES) { + JsonParser p = createParser(mode, " 123. "); + try { + p.nextToken(); + fail("Should not pass"); + } catch (JsonParseException e) { + verifyException(e, "Decimal point not followed by a digit"); + } + p.close(); + } + } + public void testLeadingDotInDecimalAllowedAsync() throws Exception { _testLeadingDotInDecimalAllowed(jsonFactory(), MODE_DATA_INPUT); } @@ -43,6 +60,19 @@ public void testLeadingDotInDecimalAllowedReader() throws Exception { _testLeadingDotInDecimalAllowed(jsonFactory(), MODE_READER); } + public void testTrailingDotInDecimalAllowedAsync() throws Exception { + _testTrailingDotInDecimalAllowed(jsonFactory(), MODE_DATA_INPUT); + } + + public void testTrailingDotInDecimalAllowedBytes() throws Exception { + _testTrailingDotInDecimalAllowed(jsonFactory(), MODE_INPUT_STREAM); + _testTrailingDotInDecimalAllowed(jsonFactory(), MODE_INPUT_STREAM_THROTTLED); + } + + public void testTrailingDotInDecimalAllowedReader() throws Exception { + _testTrailingDotInDecimalAllowed(jsonFactory(), MODE_READER); + } + private void _testLeadingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception { JsonParser p = createParser(f, mode, " .125 "); @@ -52,4 +82,14 @@ private void _testLeadingDotInDecimalAllowed(JsonFactory f, int mode) throws Exc assertEquals(".125", p.getText()); p.close(); } + + private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception + { + JsonParser p = createParser(f, mode, " 125. "); + assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); + assertEquals(125.0, p.getValueAsDouble()); + assertEquals("125", p.getDecimalValue().toString()); + assertEquals("125.", p.getText()); + p.close(); + } } From 1ae2f529b7c644b9efea5562831bf76266d19c1c Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 21 Jun 2022 16:06:00 +0100 Subject: [PATCH 02/13] Update FastParserNonStandardNumberParsingTest.java --- .../core/read/FastParserNonStandardNumberParsingTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java index 5bb40b89d7..21c8dbfa0b 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java @@ -10,6 +10,7 @@ public class FastParserNonStandardNumberParsingTest private final JsonFactory fastFactory = JsonFactory.builder() .enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS) + .enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS) .enable(StreamReadFeature.USE_FAST_DOUBLE_PARSER) .build(); From 0bda2ca7276c042dbe6a33f0637a1bc43f2d993e Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 21 Jun 2022 16:19:21 +0100 Subject: [PATCH 03/13] remove deprecated code --- .../fasterxml/jackson/core/json/ReaderBasedJsonParser.java | 4 ++-- .../fasterxml/jackson/core/json/UTF8DataInputJsonParser.java | 2 +- .../com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java | 2 +- .../jackson/core/json/async/NonBlockingJsonParser.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java index 7bc80fd33b..a7f51fa396 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java @@ -1408,7 +1408,7 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg, } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); } } @@ -1587,7 +1587,7 @@ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOExcept } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java index 886a545c81..44b9053563 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java @@ -1165,7 +1165,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c, } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java index 5cbb2c7777..32b50e3a13 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java @@ -1638,7 +1638,7 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c, } // must be followed by sequence of ints, one minimum if (fractLen == 0) { - if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { reportUnexpectedNumberChar(c, "Decimal point not followed by a digit"); } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java index 5f977ba235..2e7bfc278c 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java @@ -1655,7 +1655,7 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce ch &= 0xFF; // but here we'll want to mask it to unsigned 8-bit // must be followed by sequence of ints, one minimum if (fractLen == 0) { - if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); } } @@ -1747,7 +1747,7 @@ protected JsonToken _finishFloatFraction() throws IOException // Ok, fraction done; what have we got next? // must be followed by sequence of ints, one minimum if (fractLen == 0) { - if (!isEnabled(Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)) { + if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) { reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit"); } } From bb13d1105e1744bd44f2a1649281cf9f944bab8b Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 21 Jun 2022 20:20:29 +0100 Subject: [PATCH 04/13] init work to support leading plus sign --- .../com/fasterxml/jackson/core/JsonParser.java | 5 +++++ .../jackson/core/json/JsonReadFeature.java | 15 +++++++++++++++ .../FastParserNonStandardNumberParsingTest.java | 1 + .../core/read/NonStandardNumberParsingTest.java | 17 +++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/core/JsonParser.java b/src/main/java/com/fasterxml/jackson/core/JsonParser.java index cdfc11f7fe..56fc81e74c 100644 --- a/src/main/java/com/fasterxml/jackson/core/JsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/JsonParser.java @@ -182,6 +182,11 @@ public enum Feature { @Deprecated ALLOW_NUMERIC_LEADING_ZEROS(false), + /** + * @deprecated Use {@link com.fasterxml.jackson.core.json.JsonReadFeature#ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS} instead + */ + ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS(false), + /** * @deprecated Use {@link com.fasterxml.jackson.core.json.JsonReadFeature#ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS} instead */ diff --git a/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java b/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java index 6b0037dd50..835b0a6267 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java +++ b/src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java @@ -107,6 +107,21 @@ public enum JsonReadFeature @SuppressWarnings("deprecation") ALLOW_LEADING_ZEROS_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS), + /** + * Feature that determines whether parser will allow + * JSON decimal numbers to start with a plus sign + * (like: +123). If enabled, no exception is thrown, and the number + * is parsed as though a leading sign had not been present. + *

+ * Since JSON specification does not allow leading plus signs, + * this is a non-standard feature, and as such disabled by default. + * + * @since 2.14 + */ + @SuppressWarnings("deprecation") + ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS), + + /** * Feature that determines whether parser will allow * JSON decimal numbers to start with a decimal point diff --git a/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java index 21c8dbfa0b..ab4a64f41f 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java @@ -9,6 +9,7 @@ public class FastParserNonStandardNumberParsingTest { private final JsonFactory fastFactory = JsonFactory.builder() + .enable(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS) .enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS) .enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS) .enable(StreamReadFeature.USE_FAST_DOUBLE_PARSER) diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java index 996412a66f..8c0747915c 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java @@ -7,6 +7,7 @@ public class NonStandardNumberParsingTest extends com.fasterxml.jackson.core.BaseTest { private final JsonFactory JSON_F = JsonFactory.builder() + .enable(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS) .enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS) .enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS) .build(); @@ -31,6 +32,22 @@ public void testLeadingDotInDecimal() throws Exception { } } + /* + * The format "+NNN" (as opposed to "NNN") is not valid JSON, so this should fail + */ + public void testLeadingPlusSignInDecimal() throws Exception { + for (int mode : ALL_MODES) { + JsonParser p = createParser(mode, " +123 "); + try { + p.nextToken(); + fail("Should not pass"); + } catch (JsonParseException e) { + verifyException(e, "Unexpected character ('.'"); + } + p.close(); + } + } + /** * The format "NNN." (as opposed to "NNN") is not valid JSON, so this should fail */ From d978b86d33efb0e5319bdfab4dea166510166cca Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 21 Jun 2022 20:33:14 +0100 Subject: [PATCH 05/13] add tests --- .../core/json/ReaderBasedJsonParser.java | 4 +++ .../core/json/UTF8DataInputJsonParser.java | 4 +++ .../core/json/UTF8StreamJsonParser.java | 4 +++ .../read/NonStandardNumberParsingTest.java | 25 ++++++++++++++++++- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java index a7f51fa396..7b2168e74f 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java @@ -740,6 +740,10 @@ public final JsonToken nextToken() throws IOException // Ok: we must have a value... what is it? + if (i == '+' && isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + return nextToken(); + } + JsonToken t; switch (i) { diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java index 44b9053563..07d11fe502 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java @@ -618,6 +618,10 @@ public JsonToken nextToken() throws IOException return _currToken; } + if (i == INT_PLUS && isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + return nextToken(); + } + // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { if (i != INT_COMMA) { diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java index 32b50e3a13..a68d4a5e4a 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java @@ -772,6 +772,10 @@ public JsonToken nextToken() throws IOException return (_currToken = JsonToken.END_OBJECT); } + if (i == INT_PLUS && isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + return nextToken(); + } + // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { if (i != INT_COMMA) { diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java index 8c0747915c..98bc4a138a 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java @@ -42,7 +42,7 @@ public void testLeadingPlusSignInDecimal() throws Exception { p.nextToken(); fail("Should not pass"); } catch (JsonParseException e) { - verifyException(e, "Unexpected character ('.'"); + verifyException(e, "expected digit (0-9) to follow minus sign, for valid numeric value"); } p.close(); } @@ -90,6 +90,19 @@ public void testTrailingDotInDecimalAllowedReader() throws Exception { _testTrailingDotInDecimalAllowed(jsonFactory(), MODE_READER); } + public void testLeadingPlusSignInDecimalAllowedAsync() throws Exception { + _testLeadingPlusSignInDecimalAllowed(jsonFactory(), MODE_DATA_INPUT); + } + + public void testLeadingPlusSignInDecimalAllowedBytes() throws Exception { + _testLeadingPlusSignInDecimalAllowed(jsonFactory(), MODE_INPUT_STREAM); + _testLeadingPlusSignInDecimalAllowed(jsonFactory(), MODE_INPUT_STREAM_THROTTLED); + } + + public void testLeadingPlusSignInDecimalAllowedReader() throws Exception { + _testLeadingPlusSignInDecimalAllowed(jsonFactory(), MODE_READER); + } + private void _testLeadingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception { JsonParser p = createParser(f, mode, " .125 "); @@ -100,6 +113,16 @@ private void _testLeadingDotInDecimalAllowed(JsonFactory f, int mode) throws Exc p.close(); } + private void _testLeadingPlusSignInDecimalAllowed(JsonFactory f, int mode) throws Exception + { + JsonParser p = createParser(f, mode, " +125 "); + assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken()); + assertEquals(125.0, p.getValueAsDouble()); + assertEquals("125", p.getDecimalValue().toString()); + assertEquals("125", p.getText()); + p.close(); + } + private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception { JsonParser p = createParser(f, mode, " 125. "); From ccb40e1b2deccc7002c3a6b3ca7884c9175c16c8 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 21 Jun 2022 20:37:45 +0100 Subject: [PATCH 06/13] Update NonStandardNumberParsingTest.java --- .../read/NonStandardNumberParsingTest.java | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java index 98bc4a138a..12ee74f8b6 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java @@ -105,31 +105,43 @@ public void testLeadingPlusSignInDecimalAllowedReader() throws Exception { private void _testLeadingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception { - JsonParser p = createParser(f, mode, " .125 "); - assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); - assertEquals(0.125, p.getValueAsDouble()); - assertEquals("0.125", p.getDecimalValue().toString()); - assertEquals(".125", p.getText()); - p.close(); + try (JsonParser p = createParser(f, mode, " .125 ")) { + assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); + assertEquals(0.125, p.getValueAsDouble()); + assertEquals("0.125", p.getDecimalValue().toString()); + assertEquals(".125", p.getText()); + } } private void _testLeadingPlusSignInDecimalAllowed(JsonFactory f, int mode) throws Exception { - JsonParser p = createParser(f, mode, " +125 "); - assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken()); - assertEquals(125.0, p.getValueAsDouble()); - assertEquals("125", p.getDecimalValue().toString()); - assertEquals("125", p.getText()); - p.close(); + try (JsonParser p = createParser(f, mode, " +125 ")) { + assertEquals(JsonToken.VALUE_NUMBER_INT, p.nextToken()); + assertEquals(125.0, p.getValueAsDouble()); + assertEquals("125", p.getDecimalValue().toString()); + assertEquals("125", p.getText()); + } + try (JsonParser p = createParser(f, mode, " +.125 ")) { + assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); + assertEquals(0.125, p.getValueAsDouble()); + assertEquals("0.125", p.getDecimalValue().toString()); + assertEquals(".125", p.getText()); + } } private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception { - JsonParser p = createParser(f, mode, " 125. "); - assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); - assertEquals(125.0, p.getValueAsDouble()); - assertEquals("125", p.getDecimalValue().toString()); - assertEquals("125.", p.getText()); - p.close(); + try (JsonParser p = createParser(f, mode, " 125. ")) { + assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); + assertEquals(125.0, p.getValueAsDouble()); + assertEquals("125", p.getDecimalValue().toString()); + assertEquals("125.", p.getText()); + } + try (JsonParser p = createParser(f, mode, " 125. ")) { + assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); + assertEquals(125.0, p.getValueAsDouble()); + assertEquals("125", p.getDecimalValue().toString()); + assertEquals("125.", p.getText()); + } } } From 3dae2712d26e3721e05b207e5237c72db69f19aa Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 22 Jun 2022 10:37:14 +0100 Subject: [PATCH 07/13] avoid recursion (because that approach allows multiple leading +) --- .../core/json/ReaderBasedJsonParser.java | 34 ++++++++---- .../core/json/UTF8StreamJsonParser.java | 53 ++++++++++++------- .../read/NonStandardNumberParsingTest.java | 2 + 3 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java index 7b2168e74f..797dcb14fd 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java @@ -781,12 +781,14 @@ public final JsonToken nextToken() throws IOException break; case '-': - /* Should we have separate handling for plus? Although - * it is not allowed per se, it may be erroneously used, - * and could be indicate by a more specific error message. - */ t = _parseNegNumber(); break; + case '+': + if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + _handleOddValue(i); + } + t = _parsePosNumber(); + break; case '.': // [core#61]] t = _parseFloatThatStartsWithPeriod(); break; @@ -1457,24 +1459,34 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg, return resetFloat(neg, intLen, fractLen, expLen); } + protected final JsonToken _parsePosNumber() throws IOException + { + return _parsePossibleNumber(false); + } + protected final JsonToken _parseNegNumber() throws IOException + { + return _parsePossibleNumber(true); + } + + private JsonToken _parsePossibleNumber(boolean negative) throws IOException { int ptr = _inputPtr; - int startPtr = ptr-1; // to include sign/digit already read + int startPtr = negative ? ptr-1 : ptr; // to include sign/digit already read final int inputLen = _inputEnd; if (ptr >= inputLen) { - return _parseNumber2(true, startPtr); + return _parseNumber2(negative, startPtr); } int ch = _inputBuffer[ptr++]; // First check: must have a digit to follow minus sign if (ch > INT_9 || ch < INT_0) { _inputPtr = ptr; - return _handleInvalidNumberStart(ch, true); + return _handleInvalidNumberStart(ch, negative); } // One special case, leading zero(es): if (ch == INT_0) { - return _parseNumber2(true, startPtr); + return _parseNumber2(negative, startPtr); } int intLen = 1; // already got one @@ -1482,7 +1494,7 @@ protected final JsonToken _parseNegNumber() throws IOException int_loop: while (true) { if (ptr >= inputLen) { - return _parseNumber2(true, startPtr); + return _parseNumber2(negative, startPtr); } ch = (int) _inputBuffer[ptr++]; if (ch < INT_0 || ch > INT_9) { @@ -1493,7 +1505,7 @@ protected final JsonToken _parseNegNumber() throws IOException if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) { _inputPtr = ptr; - return _parseFloat(ch, startPtr, ptr, true, intLen); + return _parseFloat(ch, startPtr, ptr, negative, intLen); } --ptr; _inputPtr = ptr; @@ -1502,7 +1514,7 @@ protected final JsonToken _parseNegNumber() throws IOException } int len = ptr-startPtr; _textBuffer.resetWithShared(_inputBuffer, startPtr, len); - return resetInt(true, intLen); + return resetInt(negative, intLen); } /** diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java index a68d4a5e4a..e4d581817f 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java @@ -772,10 +772,6 @@ public JsonToken nextToken() throws IOException return (_currToken = JsonToken.END_OBJECT); } - if (i == INT_PLUS && isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - return nextToken(); - } - // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { if (i != INT_COMMA) { @@ -818,9 +814,12 @@ public JsonToken nextToken() throws IOException case '-': t = _parseNegNumber(); break; - - // Should we have separate handling for plus? Although it is not allowed per se, - // it may be erroneously used, and could be indicate by a more specific error message. + case '+': + if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + _handleUnexpectedValue(i); + } + t = _parsePosNumber(); + break; case '.': // [core#611]: t = _parseFloatThatStartsWithPeriod(); break; @@ -886,9 +885,11 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException return (_currToken = JsonToken.VALUE_NULL); case '-': return (_currToken = _parseNegNumber()); - - // Should we have separate handling for plus? Although it is not allowed per se, - // it may be erroneously used, and could be indicate by a more specific error message. + case '+': + if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + _handleUnexpectedValue(i); + } + return (_currToken = _parsePosNumber()); case '.': // [core#611]: return (_currToken = _parseFloatThatStartsWithPeriod()); case '0': @@ -1479,14 +1480,26 @@ protected JsonToken _parsePosNumber(int c) throws IOException // And there we have it! return resetInt(false, intLen); } - + + protected JsonToken _parsePosNumber() throws IOException + { + return _parsePossibleNumber(false); + } + protected JsonToken _parseNegNumber() throws IOException + { + return _parsePossibleNumber(true); + } + + private JsonToken _parsePossibleNumber(boolean negative) throws IOException { char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int outPtr = 0; - // Need to prepend sign? - outBuf[outPtr++] = '-'; + if (negative) { + // Need to prepend sign? + outBuf[outPtr++] = '-'; + } // Must have something after sign too if (_inputPtr >= _inputEnd) { _loadMoreGuaranteed(); @@ -1496,13 +1509,13 @@ protected JsonToken _parseNegNumber() throws IOException if (c <= INT_0) { // One special case: if first char is 0, must not be followed by a digit if (c != INT_0) { - return _handleInvalidNumberStart(c, true); + return _handleInvalidNumberStart(c, negative); } c = _verifyNoLeadingZeroes(); } else if (c > INT_9) { - return _handleInvalidNumberStart(c, true); + return _handleInvalidNumberStart(c, negative); } - + // Ok: we can first just add digit we saw first: outBuf[outPtr++] = (char) c; int intLen = 1; @@ -1514,7 +1527,7 @@ protected JsonToken _parseNegNumber() throws IOException while (true) { if (_inputPtr >= end) { // Long enough to be split across boundary, so: - return _parseNumber2(outBuf, outPtr, true, intLen); + return _parseNumber2(outBuf, outPtr, negative, intLen); } c = (int) _inputBuffer[_inputPtr++] & 0xFF; if (c < INT_0 || c > INT_9) { @@ -1524,9 +1537,9 @@ protected JsonToken _parseNegNumber() throws IOException outBuf[outPtr++] = (char) c; } if (c == INT_PERIOD || c == INT_e || c == INT_E) { - return _parseFloat(outBuf, outPtr, c, true, intLen); + return _parseFloat(outBuf, outPtr, c, negative, intLen); } - + --_inputPtr; // to push back trailing char (comma etc) _textBuffer.setCurrentLength(outPtr); // As per #105, need separating space between root values; check here @@ -1535,7 +1548,7 @@ protected JsonToken _parseNegNumber() throws IOException } // And there we have it! - return resetInt(true, intLen); + return resetInt(negative, intLen); } // Method called to handle parsing when input is split across buffer boundary diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java index 12ee74f8b6..ca3ac639c4 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java @@ -121,12 +121,14 @@ private void _testLeadingPlusSignInDecimalAllowed(JsonFactory f, int mode) throw assertEquals("125", p.getDecimalValue().toString()); assertEquals("125", p.getText()); } + /* try (JsonParser p = createParser(f, mode, " +.125 ")) { assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); assertEquals(0.125, p.getValueAsDouble()); assertEquals("0.125", p.getDecimalValue().toString()); assertEquals(".125", p.getText()); } + */ } private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception From b22105534d21cfcf3a0eb1761e4b0e51f8eaf936 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 22 Jun 2022 10:38:32 +0100 Subject: [PATCH 08/13] Update ReaderBasedJsonParser.java --- .../fasterxml/jackson/core/json/ReaderBasedJsonParser.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java index 797dcb14fd..f3190078a4 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java @@ -740,10 +740,6 @@ public final JsonToken nextToken() throws IOException // Ok: we must have a value... what is it? - if (i == '+' && isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - return nextToken(); - } - JsonToken t; switch (i) { From 5a61dfb7569f69d9c537ea69c8c341ee14e655ef Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 22 Jun 2022 10:45:58 +0100 Subject: [PATCH 09/13] avoid recursion --- .../core/json/UTF8DataInputJsonParser.java | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java index 07d11fe502..a40e5536ac 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java @@ -618,10 +618,6 @@ public JsonToken nextToken() throws IOException return _currToken; } - if (i == INT_PLUS && isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - return nextToken(); - } - // Nope: do we then expect a comma? if (_parsingContext.expectComma()) { if (i != INT_COMMA) { @@ -664,10 +660,13 @@ public JsonToken nextToken() throws IOException case '-': t = _parseNegNumber(); break; - - // Should we have separate handling for plus? Although - // it is not allowed per se, it may be erroneously used, - // and could be indicate by a more specific error message. + case '+': + if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + t = _handleUnexpectedValue(i); + } else { + t = _parsePosNumber(); + } + break; case '.': // as per [core#611] t = _parseFloatThatStartsWithPeriod(); break; @@ -733,9 +732,11 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException return (_currToken = JsonToken.VALUE_NULL); case '-': return (_currToken = _parseNegNumber()); - // Should we have separate handling for plus? Although it is not allowed - // per se, it may be erroneously used, and could be indicated by a more - // specific error message. + case '+': + if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { + return _handleUnexpectedValue(i); + } + return (_currToken = _parsePosNumber()); case '.': // as per [core#611] return (_currToken = _parseFloatThatStartsWithPeriod()); case '0': @@ -1071,14 +1072,26 @@ protected JsonToken _parsePosNumber(int c) throws IOException // And there we have it! return resetInt(false, intLen); } - + + protected JsonToken _parsePosNumber() throws IOException + { + return _parsePossibleNumber(false); + } + protected JsonToken _parseNegNumber() throws IOException + { + return _parsePossibleNumber(true); + } + + private JsonToken _parsePossibleNumber(boolean negative) throws IOException { char[] outBuf = _textBuffer.emptyAndGetCurrentSegment(); int outPtr = 0; - // Need to prepend sign? - outBuf[outPtr++] = '-'; + if (negative) { + // Need to prepend sign? + outBuf[outPtr++] = '-'; + } int c = _inputData.readUnsignedByte(); outBuf[outPtr++] = (char) c; // Note: must be followed by a digit @@ -1087,11 +1100,11 @@ protected JsonToken _parseNegNumber() throws IOException if (c == INT_0) { c = _handleLeadingZeroes(); } else { - return _handleInvalidNumberStart(c, true); + return _handleInvalidNumberStart(c, negative); } } else { if (c > INT_9) { - return _handleInvalidNumberStart(c, true); + return _handleInvalidNumberStart(c, negative); } c = _inputData.readUnsignedByte(); } @@ -1105,7 +1118,7 @@ protected JsonToken _parseNegNumber() throws IOException c = _inputData.readUnsignedByte(); } if (c == '.' || c == 'e' || c == 'E') { - return _parseFloat(outBuf, outPtr, c, true, intLen); + return _parseFloat(outBuf, outPtr, c, negative, intLen); } _textBuffer.setCurrentLength(outPtr); // As per [core#105], need separating space between root values; check here @@ -1114,7 +1127,7 @@ protected JsonToken _parseNegNumber() throws IOException _verifyRootSpace(); } // And there we have it! - return resetInt(true, intLen); + return resetInt(negative, intLen); } /** From d0c5805f8e5eab72c43924002d346914e18f0038 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 22 Jun 2022 12:13:04 +0100 Subject: [PATCH 10/13] try to fix infinity tests --- .../jackson/core/json/ReaderBasedJsonParser.java | 7 ++++--- .../jackson/core/json/UTF8DataInputJsonParser.java | 8 ++++++-- .../jackson/core/json/UTF8StreamJsonParser.java | 7 ++++--- .../core/read/NonStandardParserFeaturesTest.java | 10 +++++----- 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java index f3190078a4..0d4aa74014 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java @@ -781,9 +781,10 @@ public final JsonToken nextToken() throws IOException break; case '+': if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - _handleOddValue(i); + t = _handleOddValue(i); + } else { + t = _parsePosNumber(); } - t = _parsePosNumber(); break; case '.': // [core#61]] t = _parseFloatThatStartsWithPeriod(); @@ -1465,7 +1466,7 @@ protected final JsonToken _parseNegNumber() throws IOException return _parsePossibleNumber(true); } - private JsonToken _parsePossibleNumber(boolean negative) throws IOException + private JsonToken _parsePossibleNumber(final boolean negative) throws IOException { int ptr = _inputPtr; int startPtr = negative ? ptr-1 : ptr; // to include sign/digit already read diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java index a40e5536ac..8a6150b528 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java @@ -662,7 +662,11 @@ public JsonToken nextToken() throws IOException break; case '+': if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - t = _handleUnexpectedValue(i); + if (isEnabled(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS.mappedFeature())) { + t = _handleInvalidNumberStart(i, false); + } else { + t = _handleUnexpectedValue(i); + } } else { t = _parsePosNumber(); } @@ -734,7 +738,7 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException return (_currToken = _parseNegNumber()); case '+': if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - return _handleUnexpectedValue(i); + return (_currToken = _handleUnexpectedValue(i)); } return (_currToken = _parsePosNumber()); case '.': // as per [core#611] diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java index e4d581817f..864df1b72c 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java @@ -816,9 +816,10 @@ public JsonToken nextToken() throws IOException break; case '+': if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - _handleUnexpectedValue(i); + t = _handleUnexpectedValue(i); + } else { + t = _parsePosNumber(); } - t = _parsePosNumber(); break; case '.': // [core#611]: t = _parseFloatThatStartsWithPeriod(); @@ -887,7 +888,7 @@ private final JsonToken _nextTokenNotInObject(int i) throws IOException return (_currToken = _parseNegNumber()); case '+': if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - _handleUnexpectedValue(i); + return (_currToken = _handleUnexpectedValue(i)); } return (_currToken = _parsePosNumber()); case '.': // [core#611]: diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java index 172c066f0b..3d745003a3 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardParserFeaturesTest.java @@ -20,10 +20,10 @@ public void testDefaults() { public void testNonStandardAnyCharQuoting() throws Exception { - _testNonStandarBackslashQuoting(MODE_INPUT_STREAM); - _testNonStandarBackslashQuoting(MODE_INPUT_STREAM_THROTTLED); - _testNonStandarBackslashQuoting(MODE_DATA_INPUT); - _testNonStandarBackslashQuoting(MODE_READER); + _testNonStandardBackslashQuoting(MODE_INPUT_STREAM); + _testNonStandardBackslashQuoting(MODE_INPUT_STREAM_THROTTLED); + _testNonStandardBackslashQuoting(MODE_DATA_INPUT); + _testNonStandardBackslashQuoting(MODE_READER); } public void testLeadingZeroesUTF8() throws Exception { @@ -64,7 +64,7 @@ public void testAllowInfinity() throws Exception { /**************************************************************** */ - private void _testNonStandarBackslashQuoting(int mode) throws Exception + private void _testNonStandardBackslashQuoting(int mode) throws Exception { // first: verify that we get an exception final String JSON = quote("\\'"); From 95d3a58e2c186bca6075dc82510f777c93c4e384 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 22 Jun 2022 12:14:17 +0100 Subject: [PATCH 11/13] Update UTF8DataInputJsonParser.java --- .../jackson/core/json/UTF8DataInputJsonParser.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java index 8a6150b528..d9c04fc8fe 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java @@ -662,11 +662,7 @@ public JsonToken nextToken() throws IOException break; case '+': if (!isEnabled(JsonReadFeature.ALLOW_LEADING_PLUS_SIGN_FOR_NUMBERS.mappedFeature())) { - if (isEnabled(JsonReadFeature.ALLOW_NON_NUMERIC_NUMBERS.mappedFeature())) { - t = _handleInvalidNumberStart(i, false); - } else { - t = _handleUnexpectedValue(i); - } + t = _handleUnexpectedValue(i); } else { t = _parsePosNumber(); } From 405a03c5b9ea80a14674857aa94a9c4f2747e408 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 22 Jun 2022 12:18:01 +0100 Subject: [PATCH 12/13] Update NonStandardNumberParsingTest.java --- .../core/read/NonStandardNumberParsingTest.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java index ca3ac639c4..a5cd4962e3 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java @@ -121,14 +121,12 @@ private void _testLeadingPlusSignInDecimalAllowed(JsonFactory f, int mode) throw assertEquals("125", p.getDecimalValue().toString()); assertEquals("125", p.getText()); } - /* - try (JsonParser p = createParser(f, mode, " +.125 ")) { + try (JsonParser p = createParser(f, mode, " +0.125 ")) { assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); assertEquals(0.125, p.getValueAsDouble()); assertEquals("0.125", p.getDecimalValue().toString()); - assertEquals(".125", p.getText()); + assertEquals("0.125", p.getText()); } - */ } private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception @@ -139,11 +137,5 @@ private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Ex assertEquals("125", p.getDecimalValue().toString()); assertEquals("125.", p.getText()); } - try (JsonParser p = createParser(f, mode, " 125. ")) { - assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); - assertEquals(125.0, p.getValueAsDouble()); - assertEquals("125", p.getDecimalValue().toString()); - assertEquals("125.", p.getText()); - } } } From 2fba4df50c9c42e4263182b840d26dacf277297c Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Wed, 22 Jun 2022 12:24:10 +0100 Subject: [PATCH 13/13] extra test case --- .../fasterxml/jackson/core/json/ReaderBasedJsonParser.java | 3 +++ .../jackson/core/json/UTF8DataInputJsonParser.java | 2 ++ .../fasterxml/jackson/core/json/UTF8StreamJsonParser.java | 3 +++ .../jackson/core/read/NonStandardNumberParsingTest.java | 6 ++++++ 4 files changed, 14 insertions(+) diff --git a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java index 0d4aa74014..ab683f8624 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java @@ -1479,6 +1479,9 @@ private JsonToken _parsePossibleNumber(final boolean negative) throws IOExceptio // First check: must have a digit to follow minus sign if (ch > INT_9 || ch < INT_0) { _inputPtr = ptr; + if (ch == INT_PERIOD) { + return _parseFloatThatStartsWithPeriod(); + } return _handleInvalidNumberStart(ch, negative); } // One special case, leading zero(es): diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java index d9c04fc8fe..1fe8c7600b 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java @@ -1099,6 +1099,8 @@ private JsonToken _parsePossibleNumber(boolean negative) throws IOException // One special case: if first char is 0 need to check no leading zeroes if (c == INT_0) { c = _handleLeadingZeroes(); + } else if (c == INT_PERIOD) { + return _parseFloatThatStartsWithPeriod(); } else { return _handleInvalidNumberStart(c, negative); } diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java index 864df1b72c..87af9a297a 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java @@ -1510,6 +1510,9 @@ private JsonToken _parsePossibleNumber(boolean negative) throws IOException if (c <= INT_0) { // One special case: if first char is 0, must not be followed by a digit if (c != INT_0) { + if (c == INT_PERIOD) { + return _parseFloatThatStartsWithPeriod(); + } return _handleInvalidNumberStart(c, negative); } c = _verifyNoLeadingZeroes(); diff --git a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java index a5cd4962e3..bcf6f662d3 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java @@ -127,6 +127,12 @@ private void _testLeadingPlusSignInDecimalAllowed(JsonFactory f, int mode) throw assertEquals("0.125", p.getDecimalValue().toString()); assertEquals("0.125", p.getText()); } + try (JsonParser p = createParser(f, mode, " +.125 ")) { + assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken()); + assertEquals(0.125, p.getValueAsDouble()); + assertEquals("0.125", p.getDecimalValue().toString()); + assertEquals(".125", p.getText()); + } } private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception