[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
This commit is contained in:
Gary D. Gregory 2013-04-08 20:34:49 +00:00
parent 60cc83af7f
commit 75b9a4ba4e
5 changed files with 51 additions and 13 deletions

View File

@ -63,6 +63,7 @@ public class CSVFormat implements Serializable {
private boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values? private boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values?
private boolean ignoreEmptyLines; private boolean ignoreEmptyLines;
private String recordSeparator; // for outputs private String recordSeparator; // for outputs
private String nullToString; // for outputs
private String[] header; private String[] header;
/** /**
@ -74,7 +75,7 @@ public class CSVFormat implements Serializable {
*/ */
// package protected to give access without needing a synthetic accessor // package protected to give access without needing a synthetic accessor
CSVFormatBuilder(final char delimiter){ CSVFormatBuilder(final char delimiter){
this(delimiter, null, null, null, null, false, false, null, null); this(delimiter, null, null, null, null, false, false, null, Constants.EMPTY, null);
} }
/** /**
@ -94,10 +95,11 @@ public class CSVFormat implements Serializable {
* <tt>true</tt> when whitespaces enclosing values should be ignored * <tt>true</tt> when whitespaces enclosing values should be ignored
* @param ignoreEmptyLines * @param ignoreEmptyLines
* <tt>true</tt> when the parser should skip empty lines * <tt>true</tt> when the parser should skip empty lines
* @param recordSeparator * @param nullToString TODO
* the line separator to use for output
* @param header * @param header
* the header * the header
* @param recordSeparator
* the line separator to use for output
* @throws IllegalArgumentException if the delimiter is a line break character * @throws IllegalArgumentException if the delimiter is a line break character
*/ */
// package protected for use by test code // package protected for use by test code
@ -105,7 +107,7 @@ public class CSVFormat implements Serializable {
final Quote quotePolicy, final Character commentStart, final Quote quotePolicy, final Character commentStart,
final Character escape, final boolean ignoreSurroundingSpaces, final Character escape, final boolean ignoreSurroundingSpaces,
final boolean ignoreEmptyLines, final String lineSeparator, final boolean ignoreEmptyLines, final String lineSeparator,
final String[] header) { String nullToString, final String[] header) {
if (isLineBreak(delimiter)) { if (isLineBreak(delimiter)) {
throw new IllegalArgumentException("The delimiter cannot be a line break"); throw new IllegalArgumentException("The delimiter cannot be a line break");
} }
@ -117,6 +119,7 @@ public class CSVFormat implements Serializable {
this.ignoreSurroundingSpaces = ignoreSurroundingSpaces; this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
this.ignoreEmptyLines = ignoreEmptyLines; this.ignoreEmptyLines = ignoreEmptyLines;
this.recordSeparator = lineSeparator; this.recordSeparator = lineSeparator;
this.nullToString = nullToString;
this.header = header; this.header = header;
} }
@ -132,7 +135,7 @@ public class CSVFormat implements Serializable {
this(format.delimiter, format.quoteChar, format.quotePolicy, this(format.delimiter, format.quoteChar, format.quotePolicy,
format.commentStart, format.escape, format.commentStart, format.escape,
format.ignoreSurroundingSpaces, format.ignoreEmptyLines, format.ignoreSurroundingSpaces, format.ignoreEmptyLines,
format.recordSeparator, format.header); format.recordSeparator, format.nullToString, format.header);
} }
/** /**
@ -143,7 +146,7 @@ public class CSVFormat implements Serializable {
public CSVFormat build() { public CSVFormat build() {
validate(); validate();
return new CSVFormat(delimiter, quoteChar, quotePolicy, commentStart, escape, return new CSVFormat(delimiter, quoteChar, quotePolicy, commentStart, escape,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, header); ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullToString, header);
} }
/** /**
@ -327,6 +330,19 @@ public class CSVFormat implements Serializable {
return this; return this;
} }
/**
* Sets the String to use for null values for output.
*
* @param nullToString
* the String to use for null values for output.
*
* @return This builder with the the specified output record separator
*/
public CSVFormatBuilder withNullToString(final String nullToString) {
this.nullToString = nullToString;
return this;
}
/** /**
* Sets the quoteChar of the format to the specified character. * Sets the quoteChar of the format to the specified character.
* *
@ -423,7 +439,8 @@ public class CSVFormat implements Serializable {
* @return a standard comma separated format builder, as for {@link #RFC4180} but allowing empty lines. * @return a standard comma separated format builder, as for {@link #RFC4180} but allowing empty lines.
*/ */
public static CSVFormatBuilder newBuilder() { public static CSVFormatBuilder newBuilder() {
return new CSVFormatBuilder(COMMA, DOUBLE_QUOTE_CHAR, null, null, null, false, true, CRLF, null); return new CSVFormatBuilder(COMMA, DOUBLE_QUOTE_CHAR, null, null, null, false, true, CRLF, Constants.EMPTY,
null);
} }
private final char delimiter; private final char delimiter;
private final Character quoteChar; private final Character quoteChar;
@ -431,11 +448,12 @@ public class CSVFormat implements Serializable {
private final Character commentStart; private final Character commentStart;
private final Character escape; private final Character escape;
private final boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values? private final boolean ignoreSurroundingSpaces; // Should leading/trailing spaces be ignored around values?
private final boolean ignoreEmptyLines; private final boolean ignoreEmptyLines;
private final String recordSeparator; // for outputs private final String recordSeparator; // for outputs
private final String nullToString; // for outputs
private final String[] header; private final String[] header;
/** /**
@ -570,6 +588,7 @@ public class CSVFormat implements Serializable {
* <tt>true</tt> when the parser should skip empty lines * <tt>true</tt> when the parser should skip empty lines
* @param recordSeparator * @param recordSeparator
* the line separator to use for output * the line separator to use for output
* @param nullToString TODO
* @param header * @param header
* the header * the header
* @throws IllegalArgumentException if the delimiter is a line break character * @throws IllegalArgumentException if the delimiter is a line break character
@ -579,7 +598,7 @@ public class CSVFormat implements Serializable {
final Quote quotePolicy, final Character commentStart, final Quote quotePolicy, final Character commentStart,
final Character escape, final boolean ignoreSurroundingSpaces, final Character escape, final boolean ignoreSurroundingSpaces,
final boolean ignoreEmptyLines, final String recordSeparator, final boolean ignoreEmptyLines, final String recordSeparator,
final String[] header) { String nullToString, final String[] header) {
if (isLineBreak(delimiter)) { if (isLineBreak(delimiter)) {
throw new IllegalArgumentException("The delimiter cannot be a line break"); throw new IllegalArgumentException("The delimiter cannot be a line break");
} }
@ -591,6 +610,7 @@ public class CSVFormat implements Serializable {
this.ignoreSurroundingSpaces = ignoreSurroundingSpaces; this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
this.ignoreEmptyLines = ignoreEmptyLines; this.ignoreEmptyLines = ignoreEmptyLines;
this.recordSeparator = recordSeparator; this.recordSeparator = recordSeparator;
this.nullToString = nullToString;
this.header = header == null ? null : header.clone(); this.header = header == null ? null : header.clone();
} }
@ -722,6 +742,15 @@ public class CSVFormat implements Serializable {
return ignoreSurroundingSpaces; return ignoreSurroundingSpaces;
} }
/**
* Returns the value to use for writing null values.
*
* @return the value to use for writing null values.
*/
public String getNullToString() {
return nullToString;
}
/** /**
* Returns the character used to encapsulate values containing special characters. * Returns the character used to encapsulate values containing special characters.
* *

View File

@ -344,7 +344,7 @@ public class CSVPrinter implements Flushable, Closeable {
*/ */
public void print(final Object value) throws IOException { public void print(final Object value) throws IOException {
// null values are considered empty // null values are considered empty
final String strValue = value == null ? EMPTY : value.toString(); final String strValue = value == null ? format.getNullToString() : value.toString();
print(value, strValue, 0, strValue.length()); print(value, strValue, 0, strValue.length());
} }

View File

@ -41,7 +41,7 @@ public class CSVFormatBuilderTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
builder = new CSVFormatBuilder('+', Character.valueOf('!'), null, Character.valueOf('#'), Character.valueOf('!'), true, true, CRLF, null); builder = new CSVFormatBuilder('+', Character.valueOf('!'), null, Character.valueOf('#'), Character.valueOf('!'), true, true, CRLF, Constants.EMPTY, null);
} }
@Test @Test

View File

@ -307,6 +307,15 @@ public class CSVPrinterTest {
printer.close(); printer.close();
} }
@Test
public void testPrintCustomNullValues() throws IOException {
final StringWriter sw = new StringWriter();
final CSVPrinter printer = new CSVPrinter(sw, CSVFormat.DEFAULT.toBuilder().withNullToString("NULL").build());
printer.printRecord("a", null, "b");
assertEquals("a,NULL,b" + recordSeparator, sw.toString());
printer.close();
}
@Test @Test
public void testQuoteAll() throws IOException { public void testQuoteAll() throws IOException {
final StringWriter sw = new StringWriter(); final StringWriter sw = new StringWriter();