Skip to content

Commit

Permalink
Per [FasterXML#106] added allowNullFields to provide the option of pr…
Browse files Browse the repository at this point in the history
…ocessing null elements of lists as empty fields or the nullCharacter during serialization instead of the default behavior which skips null elements.
  • Loading branch information
morbrian committed Jan 1, 2016
1 parent e0e8bd7 commit b6c7a0a
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -706,15 +706,20 @@ public void writeNull() throws IOException
if (!_skipValue) {
if (!_arraySeparator.isEmpty()) {
_addToArray(_schema.getNullValueOrEmpty());
} else if (!_writeContext.inObject()) { // as per [#69]
} else if (!_writeContext.inObject()) {
// [#106] write single null when allow null fields enabled
if (_schema.allowNullFields()) {
_writer.writeNull(_columnIndex());
}

// as per [#69]
// note: 'root' not enough, for case of wrap-as array, or serialize List

// or, to write 'empty Object' (for common case), would
// write single null, then finish row, like so:
/*
_writer.writeNull(_columnIndex());
finishRow();
*/
*/

} else {
_writer.writeNull(_columnIndex());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@
* the header row (if header row handling enabled): if true, they must be and
* an exception if thrown if order differs: if false, no verification is performed.
* </li>
* <li>allowNullFields (boolean) [default: false] (added in Jackson 2.7): whether to
* treat null values and objects as a field when serializing data. When enabled null
* objects as a row may result in empty rows, and null objects as a field may result
* in an empty character or the nullValue written between separators.
* </li>
* </ul>
*<p>
* Note that schemas without any columns are legal, but if no columns
Expand Down Expand Up @@ -92,6 +97,7 @@ public class CsvSchema
protected final static int ENCODING_FEATURE_ALLOW_COMMENTS = 0x0004;
protected final static int ENCODING_FEATURE_REORDER_COLUMNS = 0x0008;
protected final static int ENCODING_FEATURE_STRICT_HEADERS = 0x0010;
protected final static int ENCODING_FEATURE_ALLOW_NULL_FIELDS = 0x0020;

protected final static int DEFAULT_ENCODING_FEATURES = 0;

Expand Down Expand Up @@ -583,6 +589,11 @@ public Builder setAllowComments(boolean b) {
_feature(ENCODING_FEATURE_ALLOW_COMMENTS, b);
return this;
}

public Builder setAllowNullFields(boolean b) {
_feature(ENCODING_FEATURE_ALLOW_NULL_FIELDS, b);
return this;
}

protected final void _feature(int feature, boolean state) {
_encodingFeatures = state ? (_encodingFeatures | feature) : (_encodingFeatures & ~feature);
Expand Down Expand Up @@ -995,6 +1006,14 @@ public CsvSchema withoutComments() {
return _withFeature(ENCODING_FEATURE_ALLOW_COMMENTS, false);
}

public CsvSchema withAllowNullFields() {
return _withFeature(ENCODING_FEATURE_ALLOW_NULL_FIELDS, true);
}

public CsvSchema withoutAllowNullFields() {
return _withFeature(ENCODING_FEATURE_ALLOW_NULL_FIELDS, false);
}

protected CsvSchema _withFeature(int feature, boolean state) {
int newFeatures = state ? (_features | feature) : (_features & ~feature);
return (newFeatures == _features) ? this : new CsvSchema(this, newFeatures);
Expand Down Expand Up @@ -1157,6 +1176,7 @@ public String getSchemaType() {
public boolean skipsFirstDataRow() { return (_features & ENCODING_FEATURE_SKIP_FIRST_DATA_ROW) != 0; }
public boolean allowsComments() { return (_features & ENCODING_FEATURE_ALLOW_COMMENTS) != 0; }
public boolean strictHeaders() { return (_features & ENCODING_FEATURE_STRICT_HEADERS) != 0; }
public boolean allowNullFields() { return (_features & ENCODING_FEATURE_ALLOW_NULL_FIELDS) != 0; }

/**
* @deprecated Use {@link #usesHeader()} instead
Expand Down Expand Up @@ -1314,7 +1334,8 @@ public String toString()
sb.append(", header? ").append(usesHeader());
sb.append(", skipFirst? ").append(skipsFirstDataRow());
sb.append(", comments? ").append(allowsComments());

sb.append(", allowNullFields? ").append(allowNullFields());

sb.append(']');
return sb.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.csv.*;
Expand Down Expand Up @@ -67,15 +69,43 @@ public void testNullToStream() throws Exception {
// [dataformat-csv#53]
public void testCustomNullValue() throws Exception
{
ObjectMapper mapper = mapperForCsv();
CsvMapper mapper = mapperForCsv();
CsvSchema schema = CsvSchema.builder()
.setNullValue("n/a")
.addColumn("id")
.addColumn("desc")
.build();

String result = mapper.writer(schema).writeValueAsString(new IdDesc("id", null));
// MUST use doubling for quotes!
assertEquals("id,n/a\n", result);
}

public void testCustomNullValueInObjectListIssue106() throws Exception
{
ObjectMapper mapper = mapperForCsv();
CsvSchema schema = CsvSchema.builder()
.setArrayElementSeparator(",")
.setNullValue("n/a")
.setAllowNullFields(true)
.build();

List list = Arrays.asList("d0", null, "d2");

String result = mapper.writer(schema).writeValueAsString(list);
assertEquals("d0,n/a,d2\n", result);
}

public void testDefaultNullValueInObjectListIssue106() throws Exception
{
CsvMapper mapper = mapperForCsv();
CsvSchema schema = CsvSchema.builder()
.setArrayElementSeparator(",")
.setAllowNullFields(true)
.build();

List list = Arrays.asList("d0", null, "d2");

String result = mapper.writer(schema).writeValueAsString(list);
assertEquals("d0,,d2\n", result);
}
}

0 comments on commit b6c7a0a

Please sign in to comment.