Skip to content

Commit 75b9a4b

Browse files
committed
[CSV-97] Allow the String value for null to be customized for the CSV printer.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/csv/trunk@1465768 13f79535-47bb-0310-9956-ffa450edef68
1 parent 60cc83a commit 75b9a4b

5 files changed

Lines changed: 51 additions & 13 deletions

File tree

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

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public static class CSVFormatBuilder {
6363
private boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values?
6464
private boolean ignoreEmptyLines;
6565
private String recordSeparator; // for outputs
66+
private String nullToString; // for outputs
6667
private String[] header;
6768

6869
/**
@@ -74,7 +75,7 @@ public static class CSVFormatBuilder {
7475
*/
7576
// package protected to give access without needing a synthetic accessor
7677
CSVFormatBuilder(final char delimiter){
77-
this(delimiter, null, null, null, null, false, false, null, null);
78+
this(delimiter, null, null, null, null, false, false, null, Constants.EMPTY, null);
7879
}
7980

8081
/**
@@ -94,18 +95,19 @@ public static class CSVFormatBuilder {
9495
* <tt>true</tt> when whitespaces enclosing values should be ignored
9596
* @param ignoreEmptyLines
9697
* <tt>true</tt> when the parser should skip empty lines
97-
* @param recordSeparator
98-
* the line separator to use for output
98+
* @param nullToString TODO
9999
* @param header
100100
* the header
101+
* @param recordSeparator
102+
* the line separator to use for output
101103
* @throws IllegalArgumentException if the delimiter is a line break character
102104
*/
103105
// package protected for use by test code
104106
CSVFormatBuilder(final char delimiter, final Character quoteChar,
105107
final Quote quotePolicy, final Character commentStart,
106108
final Character escape, final boolean ignoreSurroundingSpaces,
107109
final boolean ignoreEmptyLines, final String lineSeparator,
108-
final String[] header) {
110+
String nullToString, final String[] header) {
109111
if (isLineBreak(delimiter)) {
110112
throw new IllegalArgumentException("The delimiter cannot be a line break");
111113
}
@@ -117,6 +119,7 @@ public static class CSVFormatBuilder {
117119
this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
118120
this.ignoreEmptyLines = ignoreEmptyLines;
119121
this.recordSeparator = lineSeparator;
122+
this.nullToString = nullToString;
120123
this.header = header;
121124
}
122125

@@ -132,7 +135,7 @@ public static class CSVFormatBuilder {
132135
this(format.delimiter, format.quoteChar, format.quotePolicy,
133136
format.commentStart, format.escape,
134137
format.ignoreSurroundingSpaces, format.ignoreEmptyLines,
135-
format.recordSeparator, format.header);
138+
format.recordSeparator, format.nullToString, format.header);
136139
}
137140

138141
/**
@@ -143,7 +146,7 @@ public static class CSVFormatBuilder {
143146
public CSVFormat build() {
144147
validate();
145148
return new CSVFormat(delimiter, quoteChar, quotePolicy, commentStart, escape,
146-
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, header);
149+
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullToString, header);
147150
}
148151

149152
/**
@@ -327,6 +330,19 @@ public CSVFormatBuilder withIgnoreSurroundingSpaces(final boolean ignoreSurround
327330
return this;
328331
}
329332

333+
/**
334+
* Sets the String to use for null values for output.
335+
*
336+
* @param nullToString
337+
* the String to use for null values for output.
338+
*
339+
* @return This builder with the the specified output record separator
340+
*/
341+
public CSVFormatBuilder withNullToString(final String nullToString) {
342+
this.nullToString = nullToString;
343+
return this;
344+
}
345+
330346
/**
331347
* Sets the quoteChar of the format to the specified character.
332348
*
@@ -423,19 +439,21 @@ static boolean isLineBreak(final Character c) {
423439
* @return a standard comma separated format builder, as for {@link #RFC4180} but allowing empty lines.
424440
*/
425441
public static CSVFormatBuilder newBuilder() {
426-
return new CSVFormatBuilder(COMMA, DOUBLE_QUOTE_CHAR, null, null, null, false, true, CRLF, null);
442+
return new CSVFormatBuilder(COMMA, DOUBLE_QUOTE_CHAR, null, null, null, false, true, CRLF, Constants.EMPTY,
443+
null);
427444
}
428445
private final char delimiter;
429446
private final Character quoteChar;
430447
private final Quote quotePolicy;
431448
private final Character commentStart;
432449
private final Character escape;
433450
private final boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values?
434-
435451
private final boolean ignoreEmptyLines;
436452

437453
private final String recordSeparator; // for outputs
438454

455+
private final String nullToString; // for outputs
456+
439457
private final String[] header;
440458

441459
/**
@@ -570,6 +588,7 @@ public static CSVFormatBuilder newBuilder(final CSVFormat format) {
570588
* <tt>true</tt> when the parser should skip empty lines
571589
* @param recordSeparator
572590
* the line separator to use for output
591+
* @param nullToString TODO
573592
* @param header
574593
* the header
575594
* @throws IllegalArgumentException if the delimiter is a line break character
@@ -579,7 +598,7 @@ public static CSVFormatBuilder newBuilder(final CSVFormat format) {
579598
final Quote quotePolicy, final Character commentStart,
580599
final Character escape, final boolean ignoreSurroundingSpaces,
581600
final boolean ignoreEmptyLines, final String recordSeparator,
582-
final String[] header) {
601+
String nullToString, final String[] header) {
583602
if (isLineBreak(delimiter)) {
584603
throw new IllegalArgumentException("The delimiter cannot be a line break");
585604
}
@@ -591,6 +610,7 @@ public static CSVFormatBuilder newBuilder(final CSVFormat format) {
591610
this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
592611
this.ignoreEmptyLines = ignoreEmptyLines;
593612
this.recordSeparator = recordSeparator;
613+
this.nullToString = nullToString;
594614
this.header = header == null ? null : header.clone();
595615
}
596616

@@ -722,6 +742,15 @@ public boolean getIgnoreSurroundingSpaces() {
722742
return ignoreSurroundingSpaces;
723743
}
724744

745+
/**
746+
* Returns the value to use for writing null values.
747+
*
748+
* @return the value to use for writing null values.
749+
*/
750+
public String getNullToString() {
751+
return nullToString;
752+
}
753+
725754
/**
726755
* Returns the character used to encapsulate values containing special characters.
727756
*

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
* specification of a {@link CSVFormat}.
3737
*
3838
* <p>
39-
* To parse a CSV input with tabs as separators, '"' (double-quote) as an optional value encapsulator,
39+
* To parse a CSV input with tabs as separators, '"' (double-quote) as an optional value encapsulator,
4040
* and comments starting with '#', you write:
4141
* </p>
4242
*

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public CSVPrinter(final Appendable out, final CSVFormat format) {
6767

6868
/**
6969
* Outputs the line separator.
70-
*
70+
*
7171
* @throws IOException
7272
* If an I/O error occurs
7373
*/
@@ -344,7 +344,7 @@ void printAndQuote(final Object object, final CharSequence value,
344344
*/
345345
public void print(final Object value) throws IOException {
346346
// null values are considered empty
347-
final String strValue = value == null ? EMPTY : value.toString();
347+
final String strValue = value == null ? format.getNullToString() : value.toString();
348348
print(value, strValue, 0, strValue.length());
349349
}
350350

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class CSVFormatBuilderTest {
4141

4242
@Before
4343
public void setUp() throws Exception {
44-
builder = new CSVFormatBuilder('+', Character.valueOf('!'), null, Character.valueOf('#'), Character.valueOf('!'), true, true, CRLF, null);
44+
builder = new CSVFormatBuilder('+', Character.valueOf('!'), null, Character.valueOf('#'), Character.valueOf('!'), true, true, CRLF, Constants.EMPTY, null);
4545
}
4646

4747
@Test

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,15 @@ public void testPrintNullValues() throws IOException {
307307
printer.close();
308308
}
309309

310+
@Test
311+
public void testPrintCustomNullValues() throws IOException {
312+
final StringWriter sw = new StringWriter();
313+
final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.toBuilder().withNullToString("NULL").build());
314+
printer.printRecord("a", null, "b");
315+
assertEquals("a,NULL,b" + recordSeparator, sw.toString());
316+
printer.close();
317+
}
318+
310319
@Test
311320
public void testQuoteAll() throws IOException {
312321
final StringWriter sw = new StringWriter();

0 commit comments

Comments
 (0)