Skip to content

Commit a6ee67e

Browse files
[CSV-328] Fix quoted null string after disabling quote
setNullString(String) rebuilt quotedNullString by concatenating the nullable quoteCharacter field directly, so calling setQuote(null) before setNullString(...) produced a literal "nullNULLnull". Extract a shared setQuotedNullString() helper that applies the default-quote fallback, so both builder orders produce the same state. Reviewed-by: OpenAI Codex Reviewed-by: Anthropic Claude Code
1 parent ed8dbf2 commit a6ee67e

3 files changed

Lines changed: 11 additions & 2 deletions

File tree

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<action type="fix" dev="ggregory" due-to="Ruiqi Dong, Gary Gregory" issue="CSV-325">CSVParser applies characterOffset to bytePosition (#604).</action>
5454
<action type="fix" dev="ggregory" due-to="Ruiqi Dong, Gary Gregory" issue="CSV-326">CSVPrinter Reader printing with quote and escape can emit CSV that its parser cannot read back.</action>
5555
<action type="fix" dev="ggregory" due-to="Ruiqi Dong, Gary Gregory" issue="CSV-327">CSVParser applies maxRows to record numbers instead of rows produced when setRecordNumber(...) is used.</action>
56+
<action type="fix" dev="ggregory" due-to="Ruiqi Dong, Gary Gregory" issue="CSV-328">CSVFormat.Builder.setNullString(String) can build an invalid quoted null string after setQuote(null).</action>
5657
<action type="fix" dev="ggregory" due-to="OldTruckDriver, Gary Gregory" issue="CSV-326">Escape Reader values with quote and escape (#606).</action>
5758
<action type="fix" dev="ggregory" due-to="Dexter.k, Gary Gregory">Clear escape delimiter buffer before peek in Lexer.isEscapeDelimiter() (#608, #611).</action>
5859
<action type="fix" dev="ggregory" due-to="Dexter.k, Gary Gregory">Escape quote char in printWithEscapes when QuoteMode is NONE (#609).</action>

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,8 +780,7 @@ public Builder setMaxRows(final long maxRows) {
780780
*/
781781
public Builder setNullString(final String nullString) {
782782
this.nullString = nullString;
783-
this.quotedNullString = quoteCharacter + nullString + quoteCharacter;
784-
return this;
783+
return setQuotedNullString();
785784
}
786785

787786
/**
@@ -806,6 +805,10 @@ public Builder setQuote(final Character quoteCharacter) {
806805
throw new IllegalArgumentException("The quoteCharacter cannot be a line break");
807806
}
808807
this.quoteCharacter = quoteCharacter;
808+
return setQuotedNullString();
809+
}
810+
811+
private Builder setQuotedNullString() {
809812
final Character quote = quoteCharacter != null ? quoteCharacter : Constants.DOUBLE_QUOTE_CHAR;
810813
this.quotedNullString = quote + nullString + quote;
811814
return this;

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,11 @@ void testQuotedNullStringTracksQuoteCharacter() throws IOException {
10401040
builder.setQuote((Character) null);
10411041
builder.get().print(null, out, true);
10421042
assertEquals("\"NULL\"", out.toString());
1043+
// reset, reverse setter order
1044+
out.setLength(0);
1045+
builder.setNullString(null).setQuote((Character) null).setNullString("NULL");
1046+
builder.get().print(null, out, true);
1047+
assertEquals("\"NULL\"", out.toString());
10431048
}
10441049

10451050
@Test

0 commit comments

Comments
 (0)