Skip to content

Commit 718f542

Browse files
authored
Support option to enable non-standard trailing decimal point (#773)
1 parent 5c3d6ff commit 718f542

File tree

8 files changed

+80
-7
lines changed

8 files changed

+80
-7
lines changed

src/main/java/com/fasterxml/jackson/core/JsonParser.java

+6
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ public enum Feature {
188188
@Deprecated
189189
ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false),
190190

191+
/**
192+
* @deprecated Use {@link com.fasterxml.jackson.core.json.JsonReadFeature#ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS} instead
193+
*/
194+
@Deprecated
195+
ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS(false),
196+
191197
/**
192198
* Feature that allows parser to recognize set of
193199
* "Not-a-Number" (NaN) tokens as legal floating number

src/main/java/com/fasterxml/jackson/core/json/JsonReadFeature.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,28 @@ public enum JsonReadFeature
113113
* (like: .123). If enabled, no exception is thrown, and the number
114114
* is parsed as though a leading 0 had been present.
115115
*<p>
116-
* Since JSON specification does not allow leading decimal,
116+
* Since JSON specification does not allow leading decimal points,
117117
* this is a non-standard feature, and as such disabled by default.
118118
*
119119
* @since 2.11
120120
*/
121121
@SuppressWarnings("deprecation")
122122
ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS),
123123

124+
/**
125+
* Feature that determines whether parser will allow
126+
* JSON decimal numbers to end with a decimal point
127+
* (like: 123.). If enabled, no exception is thrown, and the number
128+
* is parsed as though the trailing decimal point had not been present.
129+
*<p>
130+
* Since JSON specification does not allow trailing decimal points,
131+
* this is a non-standard feature, and as such disabled by default.
132+
*
133+
* @since 2.11
134+
*/
135+
@SuppressWarnings("deprecation")
136+
ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS(false, JsonParser.Feature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS),
137+
124138
/**
125139
* Feature that allows parser to recognize set of
126140
* "Not-a-Number" (NaN) tokens as legal floating number

src/main/java/com/fasterxml/jackson/core/json/ReaderBasedJsonParser.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,9 @@ private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg,
14081408
}
14091409
// must be followed by sequence of ints, one minimum
14101410
if (fractLen == 0) {
1411-
reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
1411+
if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1412+
reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
1413+
}
14121414
}
14131415
}
14141416
int expLen = 0;
@@ -1585,7 +1587,9 @@ private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOExcept
15851587
}
15861588
// must be followed by sequence of ints, one minimum
15871589
if (fractLen == 0) {
1588-
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1590+
if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1591+
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1592+
}
15891593
}
15901594
}
15911595

src/main/java/com/fasterxml/jackson/core/json/UTF8DataInputJsonParser.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1165,7 +1165,9 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
11651165
}
11661166
// must be followed by sequence of ints, one minimum
11671167
if (fractLen == 0) {
1168-
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1168+
if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1169+
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1170+
}
11691171
}
11701172
}
11711173

src/main/java/com/fasterxml/jackson/core/json/UTF8StreamJsonParser.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1638,7 +1638,9 @@ private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
16381638
}
16391639
// must be followed by sequence of ints, one minimum
16401640
if (fractLen == 0) {
1641-
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1641+
if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1642+
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
1643+
}
16421644
}
16431645
}
16441646

src/main/java/com/fasterxml/jackson/core/json/async/NonBlockingJsonParser.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -1655,7 +1655,9 @@ protected JsonToken _startFloat(char[] outBuf, int outPtr, int ch) throws IOExce
16551655
ch &= 0xFF; // but here we'll want to mask it to unsigned 8-bit
16561656
// must be followed by sequence of ints, one minimum
16571657
if (fractLen == 0) {
1658-
reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
1658+
if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1659+
reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
1660+
}
16591661
}
16601662
break;
16611663
}
@@ -1745,7 +1747,9 @@ protected JsonToken _finishFloatFraction() throws IOException
17451747
// Ok, fraction done; what have we got next?
17461748
// must be followed by sequence of ints, one minimum
17471749
if (fractLen == 0) {
1748-
reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
1750+
if (!isEnabled(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS.mappedFeature())) {
1751+
reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
1752+
}
17491753
}
17501754
_fractLength = fractLen;
17511755
_textBuffer.setCurrentLength(outPtr);

src/test/java/com/fasterxml/jackson/core/read/FastParserNonStandardNumberParsingTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class FastParserNonStandardNumberParsingTest
1010
private final JsonFactory fastFactory =
1111
JsonFactory.builder()
1212
.enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS)
13+
.enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)
1314
.enable(StreamReadFeature.USE_FAST_DOUBLE_PARSER)
1415
.build();
1516

src/test/java/com/fasterxml/jackson/core/read/NonStandardNumberParsingTest.java

+40
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public class NonStandardNumberParsingTest
88
{
99
private final JsonFactory JSON_F = JsonFactory.builder()
1010
.enable(JsonReadFeature.ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS)
11+
.enable(JsonReadFeature.ALLOW_TRAILING_DECIMAL_POINT_FOR_NUMBERS)
1112
.build();
1213

1314
protected JsonFactory jsonFactory() {
@@ -30,6 +31,22 @@ public void testLeadingDotInDecimal() throws Exception {
3031
}
3132
}
3233

34+
/**
35+
* The format "NNN." (as opposed to "NNN") is not valid JSON, so this should fail
36+
*/
37+
public void testTrailingDotInDecimal() throws Exception {
38+
for (int mode : ALL_MODES) {
39+
JsonParser p = createParser(mode, " 123. ");
40+
try {
41+
p.nextToken();
42+
fail("Should not pass");
43+
} catch (JsonParseException e) {
44+
verifyException(e, "Decimal point not followed by a digit");
45+
}
46+
p.close();
47+
}
48+
}
49+
3350
public void testLeadingDotInDecimalAllowedAsync() throws Exception {
3451
_testLeadingDotInDecimalAllowed(jsonFactory(), MODE_DATA_INPUT);
3552
}
@@ -43,6 +60,19 @@ public void testLeadingDotInDecimalAllowedReader() throws Exception {
4360
_testLeadingDotInDecimalAllowed(jsonFactory(), MODE_READER);
4461
}
4562

63+
public void testTrailingDotInDecimalAllowedAsync() throws Exception {
64+
_testTrailingDotInDecimalAllowed(jsonFactory(), MODE_DATA_INPUT);
65+
}
66+
67+
public void testTrailingDotInDecimalAllowedBytes() throws Exception {
68+
_testTrailingDotInDecimalAllowed(jsonFactory(), MODE_INPUT_STREAM);
69+
_testTrailingDotInDecimalAllowed(jsonFactory(), MODE_INPUT_STREAM_THROTTLED);
70+
}
71+
72+
public void testTrailingDotInDecimalAllowedReader() throws Exception {
73+
_testTrailingDotInDecimalAllowed(jsonFactory(), MODE_READER);
74+
}
75+
4676
private void _testLeadingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception
4777
{
4878
JsonParser p = createParser(f, mode, " .125 ");
@@ -52,4 +82,14 @@ private void _testLeadingDotInDecimalAllowed(JsonFactory f, int mode) throws Exc
5282
assertEquals(".125", p.getText());
5383
p.close();
5484
}
85+
86+
private void _testTrailingDotInDecimalAllowed(JsonFactory f, int mode) throws Exception
87+
{
88+
JsonParser p = createParser(f, mode, " 125. ");
89+
assertEquals(JsonToken.VALUE_NUMBER_FLOAT, p.nextToken());
90+
assertEquals(125.0, p.getValueAsDouble());
91+
assertEquals("125", p.getDecimalValue().toString());
92+
assertEquals("125.", p.getText());
93+
p.close();
94+
}
5595
}

0 commit comments

Comments
 (0)