Skip to content
This repository has been archived by the owner on Jan 22, 2019. It is now read-only.

Commit

Permalink
Implement #53
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Oct 30, 2014
1 parent 9adc8c4 commit f639f66
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 42 deletions.
16 changes: 11 additions & 5 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
Project: jackson-dataformat-csv
Version: 2.4.3 (04-Oct-2014)

- Support JDK serializability of CsvMapper
- Add `CsvMapper.copy()`

------------------------------------------------------------------------
=== History: ===
=== Releases ===
------------------------------------------------------------------------

2.5.0 (not yet released)

#53: Add a way to specify "null value" (String) for `CsvGenerator` to use when writing `null`s
(part of `CsvSchema`; method `withNullValue()`)

2.4.3 (04-Oct-2014)

- Support JDK serializability of CsvMapper
- Add `CsvMapper.copy()`

2.4.2 (15-Aug-2014)

* [#47](../../jackson-dataformat-csv/issues/47): UTF-8 BOM handling not working
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -528,8 +528,7 @@ public void writeBoolean(boolean state) throws IOException, JsonGenerationExcept
public void writeNull() throws IOException, JsonGenerationException
{
_verifyValueWrite("write null value");
// !!! TODO: empty String vs String null?
_writer.write(_columnIndex(), "");
_writer.writeNull(_columnIndex());
}

@Override
Expand Down
105 changes: 86 additions & 19 deletions src/main/java/com/fasterxml/jackson/dataformat/csv/CsvSchema.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
* that include additional non-data content before real data begins (specifically
* some database dumps do this)
* </li>
* <li>nullValue (String) [default: "" (empty String)]: When asked to write Java `null`,
* this String value will be used instead.<br />
* NOTE: NOT used for reading at this point (this may change in future)
* </li>
* </ul>
*<p>
* Note that schemas without any columns are legal, but if no columns
Expand Down Expand Up @@ -77,15 +81,20 @@ public class CsvSchema
protected final static Column[] NO_COLUMNS = new Column[0];

public final static char DEFAULT_COLUMN_SEPARATOR = ',';

public final static char DEFAULT_QUOTE_CHAR = '"';

/**
* By default, nulls are written as empty Strings ("")
*/
public final static char[] DEFAULT_NULL_VALUE = new char[0];

/**
* By default, no escape character is used -- this is denoted by
* int value that does not map to a valid character
*/
public final static int DEFAULT_ESCAPE_CHAR = -1;

public final static char[] DEFAULT_LINEFEED = "\n".toCharArray();

/**
Expand All @@ -100,7 +109,7 @@ public class CsvSchema
/* Helper classes
/**********************************************************************
*/

/**
* Enumeration that defines optional type indicators that can be passed
* with schema. If used type is used to determine type of
Expand Down Expand Up @@ -192,14 +201,24 @@ public static class Builder
protected char _columnSeparator = DEFAULT_COLUMN_SEPARATOR;

// note: need to use int to allow -1 for 'none'
protected int _quoteChar = DEFAULT_QUOTE_CHAR;
protected int _quoteChar;

// note: need to use int to allow -1 for 'none'
protected int _escapeChar = DEFAULT_ESCAPE_CHAR;
protected int _escapeChar;

protected char[] _lineSeparator = DEFAULT_LINEFEED;
protected char[] _lineSeparator;

/**
* @since 2.5
*/
protected char[] _nullValue;

public Builder() { }
public Builder() {
_quoteChar = DEFAULT_QUOTE_CHAR;
_escapeChar = DEFAULT_ESCAPE_CHAR;
_lineSeparator = DEFAULT_LINEFEED;
_nullValue = DEFAULT_NULL_VALUE;
}

/**
* "Copy" constructor which creates builder that has settings of
Expand All @@ -215,6 +234,7 @@ public Builder(CsvSchema src)
_quoteChar = src._quoteChar;
_escapeChar = src._escapeChar;
_lineSeparator = src._lineSeparator;
_nullValue = src._nullValue;
_skipFirstDataRow = src._skipFirstDataRow;
}

Expand Down Expand Up @@ -327,13 +347,23 @@ public Builder setLineSeparator(char lf) {
_lineSeparator = new char[] { lf };
return this;
}

public Builder setNullValue(String nvl) {
return setNullValue(nvl.toCharArray());
}

public Builder setNullValue(char[] nvl) {
_nullValue = (nvl == null) ? DEFAULT_NULL_VALUE : nvl;
return this;
}

public CsvSchema build()
{
Column[] cols = _columns.toArray(new Column[_columns.size()]);
return new CsvSchema(cols,
_useHeader, _skipFirstDataRow,
_columnSeparator, _quoteChar, _escapeChar, _lineSeparator);
_columnSeparator, _quoteChar, _escapeChar, _lineSeparator,
_nullValue);
}

protected void _checkIndex(int index) {
Expand Down Expand Up @@ -368,11 +398,30 @@ protected void _checkIndex(int index) {
protected final int _escapeChar;

protected final char[] _lineSeparator;


/**
* @since 2.5
*/
protected final char[] _nullValue;

@Deprecated // in 2.5; remove from 2.6
public CsvSchema(Column[] columns,
boolean useHeader, boolean skipFirstDataRow,
char columnSeparator, int quoteChar, int escapeChar,
char[] lineSeparator)
{
this(columns, useHeader, skipFirstDataRow,
columnSeparator, quoteChar, escapeChar, lineSeparator,
DEFAULT_NULL_VALUE);
}

/**
* @since 2.5
*/
public CsvSchema(Column[] columns,
boolean useHeader, boolean skipFirstDataRow,
char columnSeparator, int quoteChar, int escapeChar,
char[] lineSeparator, char[] nullValue)
{
if (columns == null) {
columns = NO_COLUMNS;
Expand All @@ -384,6 +433,7 @@ public CsvSchema(Column[] columns,
_quoteChar = quoteChar;
_escapeChar = escapeChar;
_lineSeparator = lineSeparator;
_nullValue = nullValue;

// and then we may need to create a mapping
if (_columns.length == 0) {
Expand All @@ -403,7 +453,7 @@ public CsvSchema(Column[] columns,
protected CsvSchema(Column[] columns,
boolean useHeader, boolean skipFirstDataRow,
char columnSeparator, int quoteChar, int escapeChar,
char[] lineSeparator,
char[] lineSeparator, char[] nullValue,
Map<String,Column> columnsByName)
{
_columns = columns;
Expand All @@ -413,6 +463,7 @@ protected CsvSchema(Column[] columns,
_quoteChar = quoteChar;
_escapeChar = escapeChar;
_lineSeparator = lineSeparator;
_nullValue = nullValue;
_columnsByName = columnsByName;
}

Expand All @@ -428,6 +479,7 @@ protected CsvSchema(CsvSchema base, Column[] columns) {
_quoteChar = base._quoteChar;
_escapeChar = base._escapeChar;
_lineSeparator = base._lineSeparator;
_nullValue = base._nullValue;
_columnsByName = base._columnsByName;
}

Expand Down Expand Up @@ -475,7 +527,7 @@ public CsvSchema withUseHeader(boolean state) {
return (_useHeader == state) ? this
: new CsvSchema(_columns, state, _skipFirstDataRow,
_columnSeparator, _quoteChar,
_escapeChar, _lineSeparator, _columnsByName);
_escapeChar, _lineSeparator, _nullValue, _columnsByName);
}

/**
Expand All @@ -498,47 +550,57 @@ public CsvSchema withSkipFirstDataRow(boolean state) {
return (_skipFirstDataRow == state) ? this
: new CsvSchema(_columns, _useHeader, state,
_columnSeparator, _quoteChar,
_escapeChar, _lineSeparator, _columnsByName);
_escapeChar, _lineSeparator, _nullValue, _columnsByName);
}

public CsvSchema withColumnSeparator(char sep) {
return (_columnSeparator == sep) ? this :
new CsvSchema(_columns, _useHeader, _skipFirstDataRow,
sep, _quoteChar, _escapeChar, _lineSeparator, _columnsByName);
sep, _quoteChar, _escapeChar, _lineSeparator, _nullValue, _columnsByName);
}

public CsvSchema withQuoteChar(char c) {
return (_quoteChar == c) ? this :
new CsvSchema(_columns, _useHeader, _skipFirstDataRow,
_columnSeparator, c, _escapeChar, _lineSeparator, _columnsByName);
_columnSeparator, c, _escapeChar, _lineSeparator, _nullValue, _columnsByName);
}

public CsvSchema withoutQuoteChar() {
return (_quoteChar == -1) ? this :
new CsvSchema(_columns, _useHeader, _skipFirstDataRow,
_columnSeparator, -1, _escapeChar, _lineSeparator, _columnsByName);
_columnSeparator, -1, _escapeChar, _lineSeparator, _nullValue, _columnsByName);
}

public CsvSchema withEscapeChar(char c) {
return (_escapeChar == c) ? this
: new CsvSchema(_columns, _useHeader, _skipFirstDataRow,
_columnSeparator, _quoteChar, c, _lineSeparator, _columnsByName);
_columnSeparator, _quoteChar, c, _lineSeparator, _nullValue, _columnsByName);
}

public CsvSchema withoutEscapeChar() {
return (_escapeChar == -1) ? this
: new CsvSchema(_columns, _useHeader, _skipFirstDataRow,
_columnSeparator, _quoteChar, -1, _lineSeparator, _columnsByName);
_columnSeparator, _quoteChar, -1, _lineSeparator, _nullValue, _columnsByName);
}

public CsvSchema withLineSeparator(String sep) {
return new CsvSchema(_columns, _useHeader, _skipFirstDataRow,
_columnSeparator, _quoteChar, _escapeChar, sep.toCharArray(), _columnsByName);
_columnSeparator, _quoteChar, _escapeChar, sep.toCharArray(), _nullValue, _columnsByName);
}

/**
* @since 2.5
*/
public CsvSchema withNullValue(String nvl) {
return new CsvSchema(_columns, _useHeader, _skipFirstDataRow,
_columnSeparator, _quoteChar, _escapeChar, _lineSeparator,
(nvl == null) ? DEFAULT_NULL_VALUE : nvl.toCharArray(),
_columnsByName);
}

public CsvSchema withoutColumns() {
return new CsvSchema(NO_COLUMNS, _useHeader, _skipFirstDataRow,
_columnSeparator, _quoteChar, _escapeChar, _lineSeparator, _columnsByName);
_columnSeparator, _quoteChar, _escapeChar, _lineSeparator, _nullValue, _columnsByName);
}

/**
Expand Down Expand Up @@ -608,6 +670,11 @@ public String getSchemaType() {
public int getEscapeChar() { return _escapeChar; }
public char[] getLineSeparator() { return _lineSeparator; }

/**
* @since 2.5
*/
public char[] getNullValue() { return _nullValue; }

public boolean usesQuoteChar() { return _quoteChar >= 0; }
public boolean usesEscapeChar() { return _escapeChar >= 0; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,19 @@
public abstract class BufferedValue
{
protected BufferedValue() { }

public abstract void write(CsvWriter w) throws IOException;

public static BufferedValue buffered(String v) { return new TextValue(v); }
public static BufferedValue buffered(int v) { return new IntValue(v); }
public static BufferedValue buffered(long v) { return new LongValue(v); }
public static BufferedValue buffered(double v) { return new DoubleValue(v); }
public static BufferedValue buffered(boolean v) { return new BooleanValue(v); }
public static BufferedValue buffered(boolean v) {
return v ? BooleanValue.TRUE : BooleanValue.FALSE;
}
public static BufferedValue bufferedNull() {
return NullValue.std;
}

protected final static class TextValue extends BufferedValue
{
Expand Down Expand Up @@ -68,6 +73,9 @@ public void write(CsvWriter w) throws IOException {

protected final static class BooleanValue extends BufferedValue
{
public final static BooleanValue FALSE = new BooleanValue(false);
public final static BooleanValue TRUE = new BooleanValue(true);

private final boolean _value;

public BooleanValue(boolean v) { _value = v; }
Expand All @@ -77,4 +85,15 @@ public void write(CsvWriter w) throws IOException {
w.appendValue(_value);
}
}

protected final static class NullValue extends BufferedValue {
public final static NullValue std = new NullValue();

private NullValue() { }

@Override
public void write(CsvWriter w) throws IOException {
w.appendNull();
}
}
}
Loading

0 comments on commit f639f66

Please sign in to comment.