Skip to content

Commit 72ed67b

Browse files
committed
adding more details into the error message during the CSV parser issues
1 parent e1f8da1 commit 72ed67b

2 files changed

Lines changed: 75 additions & 1 deletion

File tree

src/main/java/org/apache/commons/csv/CSVParser.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,8 @@ public static CSVParser parse(final URL url, final Charset charset, final CSVFor
355355
return new CSVParser(new InputStreamReader(url.openStream(), charset), format);
356356
}
357357

358+
private int maxParsedTokenCount = 5;
359+
358360
private String headerComment;
359361

360362
private String trailerComment;
@@ -440,6 +442,44 @@ public CSVParser(final Reader reader, final CSVFormat format, final long charact
440442
this.recordNumber = recordNumber - 1;
441443
}
442444

445+
/**
446+
* Return the parsed CSV content of current reading line up until this method is called.
447+
* <p>
448+
* Maximum parsed token length set by the 'maxParsedTokenCount' is considered during the construction of return string.
449+
* </p>
450+
* <p>
451+
* Example:
452+
* </p>
453+
* </p>
454+
* If currently reading CSV record row contains following data and 'maxParsedTokenCount' is set to 5 and current reading position is col7
455+
* </p>
456+
* <pre>
457+
* col1, col2, col3, col4, col5, col6, col7
458+
* </pre>
459+
* <p>
460+
* then this would return following
461+
* </p>
462+
* <pre>
463+
* col3, col4, col5, col6, col7
464+
* </pre>
465+
* @return parsed CSV content of current reading line
466+
*/
467+
private String getLastParsedContent(){
468+
String parsedContent = "";
469+
int recordListSize = this.recordList.size();
470+
if(recordListSize > 0) {
471+
if(recordListSize <= this.maxParsedTokenCount) {
472+
parsedContent = String.join("", this.recordList.toArray(Constants.EMPTY_STRING_ARRAY));
473+
} else {
474+
// number of parsed token exceed required token count. Take the expected tokens from the end.
475+
int startIndex = recordListSize - maxParsedTokenCount;
476+
List<String> lastParsedTokenList = this.recordList.subList(startIndex, recordListSize);
477+
parsedContent = "..." + String.join(this.format.getDelimiterString(), lastParsedTokenList.toArray(Constants.EMPTY_STRING_ARRAY));
478+
}
479+
}
480+
return parsedContent;
481+
}
482+
443483
private void addRecordValue(final boolean lastRecord) {
444484
final String input = this.format.trim(this.reusableToken.content.toString());
445485
if (lastRecord && input.isEmpty() && this.format.getTrailingDelimiter()) {
@@ -767,7 +807,15 @@ CSVRecord nextRecord() throws IOException {
767807
final long startCharPosition = lexer.getCharacterPosition() + this.characterOffset;
768808
do {
769809
this.reusableToken.reset();
770-
this.lexer.nextToken(this.reusableToken);
810+
// https://issues.apache.org/jira/browse/CSV-147
811+
try{
812+
this.lexer.nextToken(this.reusableToken);
813+
} catch (IOException ioe){
814+
String errorMessage = "An error occurred while tying to parse the CSV content. Error in line: "
815+
+ this.lexer.getCurrentLineNumber() + ", position: " + this.lexer.getCharacterPosition()
816+
+ ", last parsed content: " + this.getLastParsedContent();
817+
throw new IOException(errorMessage, ioe);
818+
}
771819
switch (this.reusableToken.type) {
772820
case TOKEN:
773821
this.addRecordValue(false);

src/test/java/org/apache/commons/csv/CSVParserTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1642,4 +1642,30 @@ private void validateRecordPosition(final String lineSeparator) throws IOExcepti
16421642
parser.close();
16431643
}
16441644

1645+
@Test
1646+
public void testFaultyCSVShouldThrowErrorWithDetailedMessage() {
1647+
1648+
String csvContent = "col1,col2,col3,col4,col5,col6,col7,col8,col9,col10\n" +
1649+
"rec1,rec2,rec3,rec4,rec5,rec6,rec7,rec8,\"\"rec9\"\",rec10";
1650+
1651+
StringReader stringReader = new StringReader(csvContent);
1652+
CSVFormat csvFormat = CSVFormat.DEFAULT.builder()
1653+
.setHeader()
1654+
.setSkipHeaderRecord(true)
1655+
.build();
1656+
1657+
Exception exception = assertThrows(UncheckedIOException.class, ()-> {
1658+
Iterable<CSVRecord> records = csvFormat.parse(stringReader);
1659+
for (CSVRecord record : records) {
1660+
System.out.println(record.get(0) + " " + record.get(1) + " " + record.get(2) + " " + record.get(3) + " " + record.get(4) + " " + record.get(5) + " " + record.get(6) + " " + record.get(7) + " " + record.get(8) + " " + record.get(9));
1661+
}
1662+
});
1663+
String expectedErrorMessage = "IOException reading next record: java.io.IOException: An error occurred while tying to parse the CSV content. Error in line: 2, position: 94, last parsed content: ...rec4,rec5,rec6,rec7,rec8";
1664+
String actualMessage = exception.getMessage();
1665+
1666+
assertTrue(actualMessage.contains(expectedErrorMessage));
1667+
1668+
1669+
}
1670+
16451671
}

0 commit comments

Comments
 (0)