Skip to content

Commit b6aa5e2

Browse files
authored
Fix #564 (and some related problems) (#565)
1 parent 8ac0e9d commit b6aa5e2

4 files changed

Lines changed: 84 additions & 10 deletions

File tree

csv/src/main/java/com/fasterxml/jackson/dataformat/csv/CsvParser.java

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,10 @@ public void close() throws IOException {
544544
if (!isClosed()) {
545545
_reader.close();
546546
_ioContext.close();
547+
// 30-May-2025, tatu: was missing before 2.20
548+
if (JsonParser.Feature.CLEAR_CURRENT_TOKEN_ON_CLOSE.enabledIn(_features)) {
549+
_currToken = null;
550+
}
547551
}
548552
}
549553

@@ -1363,6 +1367,7 @@ public byte[] getBinaryValue(Base64Variant variant) throws IOException
13631367

13641368
@Override
13651369
public NumberType getNumberType() throws IOException {
1370+
_verifyNumberToken();
13661371
return _reader.getNumberType();
13671372
}
13681373

@@ -1374,41 +1379,49 @@ public NumberTypeFP getNumberTypeFP() throws IOException {
13741379

13751380
@Override
13761381
public Number getNumberValue() throws IOException {
1382+
_verifyNumberToken();
13771383
return _reader.getNumberValue(false);
13781384
}
13791385

13801386
@Override
13811387
public Number getNumberValueExact() throws IOException {
1388+
_verifyNumberToken();
13821389
return _reader.getNumberValue(true);
13831390
}
13841391

13851392
@Override
13861393
public int getIntValue() throws IOException {
1394+
_verifyNumberToken();
13871395
return _reader.getIntValue();
13881396
}
13891397

13901398
@Override
13911399
public long getLongValue() throws IOException {
1400+
_verifyNumberToken();
13921401
return _reader.getLongValue();
13931402
}
13941403

13951404
@Override
13961405
public BigInteger getBigIntegerValue() throws IOException {
1406+
_verifyNumberToken();
13971407
return _reader.getBigIntegerValue();
13981408
}
13991409

14001410
@Override
14011411
public float getFloatValue() throws IOException {
1412+
_verifyNumberToken();
14021413
return _reader.getFloatValue();
14031414
}
14041415

14051416
@Override
14061417
public double getDoubleValue() throws IOException {
1418+
_verifyNumberToken();
14071419
return _reader.getDoubleValue();
14081420
}
14091421

14101422
@Override
14111423
public BigDecimal getDecimalValue() throws IOException {
1424+
_verifyNumberToken();
14121425
return _reader.getDecimalValue();
14131426
}
14141427

@@ -1444,14 +1457,26 @@ public <T> T _reportCsvMappingError(String msg, Object... args) throws IOExcepti
14441457
throw CsvReadException.from(this, msg, _schema);
14451458
}
14461459

1447-
public void _reportParsingError(String msg) throws JsonProcessingException {
1460+
public void _reportParsingError(String msg) throws JsonProcessingException {
14481461
super._reportError(msg);
14491462
}
14501463

1451-
public void _reportUnexpectedCsvChar(int ch, String msg) throws JsonProcessingException {
1464+
public void _reportUnexpectedCsvChar(int ch, String msg) throws JsonProcessingException {
14521465
super._reportUnexpectedChar(ch, msg);
14531466
}
14541467

1468+
protected void _verifyNumberToken() throws IOException {
1469+
if (_currToken != JsonToken.VALUE_NUMBER_INT) {
1470+
_reportNotNumericError();
1471+
}
1472+
}
1473+
1474+
protected <T> T _reportNotNumericError() throws IOException {
1475+
_reportError("Current token (%s) not numeric, can not use numeric value accessors",
1476+
_currToken);
1477+
return null;
1478+
}
1479+
14551480
/*
14561481
/**********************************************************************
14571482
/* Internal methods

csv/src/main/java/com/fasterxml/jackson/dataformat/csv/impl/CsvDecoder.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,6 @@ protected BigDecimal _getBigDecimal() throws IOException{
12191219
protected void _parseNumericValue(boolean exactNumber)
12201220
throws IOException
12211221
{
1222-
// Int or float?
12231222
if (looksLikeInt()) {
12241223
_parseIntValue();
12251224
return;

csv/src/test/java/com/fasterxml/jackson/dataformat/csv/deser/StreamingCSVReadTest.java

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import org.junit.jupiter.api.Test;
66

77
import com.fasterxml.jackson.core.JsonParser.NumberType;
8+
import com.fasterxml.jackson.core.exc.StreamReadException;
9+
import com.fasterxml.jackson.core.JsonParser;
810
import com.fasterxml.jackson.core.JsonToken;
911
import com.fasterxml.jackson.core.io.SerializedString;
1012
import com.fasterxml.jackson.dataformat.csv.*;
@@ -95,17 +97,21 @@ private void _testInts(boolean useBytes, int a, int b, int c) throws Exception {
9597
assertEquals(numStr.length(), parser.getText(w));
9698
assertEquals(numStr, w.toString());
9799

100+
// 31-May-2025, tatu: as per [dataformats-text#564] must coerce first
101+
assertTrue(parser.isExpectedNumberIntToken());
98102
assertEquals(a, parser.getIntValue());
99103
assertEquals((long) a, parser.getLongValue());
100104

101105
assertEquals("b", parser.nextFieldName());
102106
assertEquals(""+b, parser.nextTextValue());
107+
assertTrue(parser.isExpectedNumberIntToken());
103108
assertEquals((long) b, parser.getLongValue());
104109
assertEquals(b, parser.getIntValue());
105110

106111
assertTrue(parser.nextFieldName(new SerializedString("c")));
107112

108113
assertToken(JsonToken.VALUE_STRING, parser.nextToken());
114+
assertTrue(parser.isExpectedNumberIntToken());
109115
assertEquals(c, parser.getIntValue());
110116
assertEquals((long) c, parser.getLongValue());
111117

@@ -117,13 +123,23 @@ private void _testInts(boolean useBytes, int a, int b, int c) throws Exception {
117123

118124
private void _testIntsExpected(boolean useBytes, int a, int b, int c) throws Exception {
119125
try (CsvParser parser = _parser(String.format("%d,%d,%d\n", a, b, c), useBytes, ABC_SCHEMA)) {
126+
_verifyGetNumberTypeFail(parser, "null");
120127
assertToken(JsonToken.START_OBJECT, parser.nextToken());
128+
_verifyGetNumberTypeFail(parser, "START_OBJECT");
121129

122130
assertToken(JsonToken.FIELD_NAME, parser.nextToken());
123131
assertEquals("a", parser.currentName());
132+
_verifyGetNumberTypeFail(parser, "FIELD_NAME");
124133

125134
// Reported as String BUT may be coerced
126135
assertToken(JsonToken.VALUE_STRING, parser.nextToken());
136+
// Exception before conversion
137+
try {
138+
parser.getIntValue();
139+
fail("Should not pass");
140+
} catch (StreamReadException e) {
141+
_verifyNonNumberTypeException(e, "VALUE_STRING");
142+
}
127143
assertTrue(parser.isExpectedNumberIntToken());
128144
assertEquals(a, parser.getIntValue());
129145
assertToken(JsonToken.VALUE_NUMBER_INT, parser.currentToken());
@@ -143,7 +159,11 @@ private void _testIntsExpected(boolean useBytes, int a, int b, int c) throws Exc
143159
assertToken(JsonToken.VALUE_NUMBER_INT, parser.currentToken());
144160

145161
assertToken(JsonToken.END_OBJECT, parser.nextToken());
146-
assertNull(parser.nextToken());
162+
_verifyGetNumberTypeFail(parser, "END_OBJECT");
163+
164+
parser.close();
165+
_verifyGetNumberTypeFail(parser, "null");
166+
assertNull(parser.currentToken());
147167
}
148168
}
149169

@@ -156,10 +176,21 @@ private void _testLongs(boolean useBytes, long a, long b) throws Exception
156176
assertToken(JsonToken.FIELD_NAME, parser.nextToken());
157177
assertEquals("a", parser.currentName());
158178
assertEquals(""+a, parser.nextTextValue());
179+
// 31-May-2025, tatu: as per [dataformats-text#564] must coerce first
180+
assertTrue(parser.isExpectedNumberIntToken());
159181
assertEquals(a, parser.getLongValue());
160182

161183
assertEquals("b", parser.nextFieldName());
162184
assertEquals(""+b, parser.nextTextValue());
185+
// Exception before conversion
186+
try {
187+
parser.getLongValue();
188+
fail("Should not pass");
189+
} catch (StreamReadException e) {
190+
_verifyNonNumberTypeException(e, "VALUE_STRING");
191+
}
192+
193+
assertTrue(parser.isExpectedNumberIntToken());
163194
assertEquals(b, parser.getLongValue());
164195

165196
assertToken(JsonToken.END_OBJECT, parser.nextToken());
@@ -178,19 +209,20 @@ private void _testDoubles(boolean useBytes, double a, double b, double c)
178209
assertToken(JsonToken.FIELD_NAME, parser.nextToken());
179210
assertEquals("a", parser.currentName());
180211
assertEquals(""+a, parser.nextTextValue());
181-
assertEquals(a, parser.getDoubleValue());
182-
assertEquals((float) a, parser.getFloatValue());
212+
// 31-May-2025, tatu: as per [dataformats-text#564] shouldn't work
213+
// assertEquals(a, parser.getDoubleValue());
214+
// assertEquals((float) a, parser.getFloatValue());
183215

184216
assertEquals("b", parser.nextFieldName());
185217
assertEquals(""+b, parser.nextTextValue());
186-
assertEquals((float) b, parser.getFloatValue());
187-
assertEquals(b, parser.getDoubleValue());
218+
// assertEquals((float) b, parser.getFloatValue());
219+
// assertEquals(b, parser.getDoubleValue());
188220

189221
assertTrue(parser.nextFieldName(new SerializedString("c")));
190222

191223
assertToken(JsonToken.VALUE_STRING, parser.nextToken());
192-
assertEquals(c, parser.getDoubleValue());
193-
assertEquals((float) c, parser.getFloatValue());
224+
// assertEquals(c, parser.getDoubleValue());
225+
// assertEquals((float) c, parser.getFloatValue());
194226

195227
assertToken(JsonToken.END_OBJECT, parser.nextToken());
196228
assertNull(parser.nextToken());
@@ -210,4 +242,20 @@ private CsvParser _parser(String csv, boolean useBytes, CsvSchema schema)
210242
p.setSchema(schema);
211243
return p;
212244
}
245+
246+
// In Jackson 2.x, non-Number token should throw exception for parser.getNumberType()
247+
private void _verifyGetNumberTypeFail(JsonParser p, String token) throws Exception
248+
{
249+
try {
250+
p.getNumberType();
251+
fail("Should not pass");
252+
} catch (StreamReadException e) {
253+
_verifyNonNumberTypeException(e, token);
254+
}
255+
}
256+
257+
private void _verifyNonNumberTypeException(Exception e, String token) throws Exception
258+
{
259+
verifyException(e, "Current token ("+token+") not numeric, can not use numeric");
260+
}
213261
}

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Active Maintainers:
1616

1717
2.20.0 (not yet released)
1818

19+
#564: (csv) `CsvParser.getNumberValue()`, related, do not throw exception
20+
for non-numeric tokens
1921
- Generate SBOMs [JSTEP-14]
2022

2123
2.19.0 (24-Apr-2025)

0 commit comments

Comments
 (0)