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

Commit

Permalink
Fix #50
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Nov 10, 2014
1 parent 1c60e9d commit c2c83f8
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 58 deletions.
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ Project: jackson-dataformat-csv

2.5.0 (not yet released)

#50: Support `JsonGenerator.Feature.IGNORE_KNOWN` for CSV, to ignoring extra columns
#53: Add a way to specify "null value" (String) for `CsvGenerator` to use when writing `null`s
(part of `CsvSchema`; method `withNullValue()`)


2.4.4 (not yet released)

#54: Encounter ArrayIndexOutOfBoundsException in the corner case delimiter or end-of-line
Expand Down
142 changes: 86 additions & 56 deletions src/main/java/com/fasterxml/jackson/dataformat/csv/CsvGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private Feature(boolean defaultState) {
_mask = (1 << ordinal());
}

public boolean enabledIn(int flags) { return (flags & getMask()) != 0; }
public boolean enabledIn(int flags) { return (flags & _mask) != 0; }
public boolean enabledByDefault() { return _defaultState; }
public int getMask() { return _mask; }
}
Expand Down Expand Up @@ -110,7 +110,7 @@ private Feature(boolean defaultState) {

// note: can not be final since we may need to re-create it for new schema
protected CsvEncoder _writer;

/*
/**********************************************************
/* Output state
Expand All @@ -129,6 +129,14 @@ private Feature(boolean defaultState) {
* field name call that was made.
*/
protected int _nextColumnByName = -1;

/**
* Flag set when property to write is unknown, and the matching value
* is to be skipped quietly.
*
* @since 2.5
*/
protected boolean _skipValue;

/*
/**********************************************************
Expand Down Expand Up @@ -251,7 +259,7 @@ public boolean canOmitFields() {
*/

@Override
public final void writeFieldName(String name) throws IOException, JsonGenerationException
public final void writeFieldName(String name) throws IOException
{
if (_writeContext.writeFieldName(name) == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
Expand All @@ -260,8 +268,7 @@ public final void writeFieldName(String name) throws IOException, JsonGeneration
}

@Override
public final void writeFieldName(SerializableString name)
throws IOException, JsonGenerationException
public final void writeFieldName(SerializableString name) throws IOException
{
// Object is a value, need to verify it's allowed
if (_writeContext.writeFieldName(name.getValue()) == JsonWriteContext.STATUS_EXPECT_VALUE) {
Expand All @@ -271,8 +278,7 @@ public final void writeFieldName(SerializableString name)
}

@Override
public final void writeStringField(String fieldName, String value)
throws IOException, JsonGenerationException
public final void writeStringField(String fieldName, String value) throws IOException
{
if (_writeContext.writeFieldName(fieldName) == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
Expand All @@ -281,39 +287,32 @@ public final void writeStringField(String fieldName, String value)
writeString(value);
}

private final void _writeFieldName(String name)
throws IOException, JsonGenerationException
private final void _writeFieldName(String name) throws IOException
{
// just find the matching index -- must have schema for that
if (_schema == null) {
_reportError("Unrecognized column '"+name+"', can not resolve without CsvSchema");
}
CsvSchema.Column col = _schema.column(name);
if (col == null) {
if (isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
_skipValue = true;
_nextColumnByName = -1;
return;
}
_reportError("Unrecognized column '"+name+"': known columns: "+_schema.getColumnDesc());

}
_skipValue = false;
// and all we do is just note index to use for following value write
_nextColumnByName = col.getIndex();
}

/*
/**********************************************************
/* Extended API, configuration
/**********************************************************
*/

public CsvGenerator enable(Feature f) {
_csvFeatures |= f.getMask();
_writer.setFeatures(_csvFeatures);
return this;
}

public CsvGenerator disable(Feature f) {
_csvFeatures &= ~f.getMask();
return this;
}

public final boolean isEnabled(Feature f) {
return (_csvFeatures & f.getMask()) != 0;
}
Expand All @@ -325,15 +324,25 @@ public CsvGenerator configure(Feature f, boolean state) {
return disable(f);
}

public CsvGenerator enable(Feature f) {
_csvFeatures |= f.getMask();
_writer.setFeatures(_csvFeatures);
return this;
}

public CsvGenerator disable(Feature f) {
_csvFeatures &= ~f.getMask();
return this;
}

/*
/**********************************************************
/* Public API: low-level I/O
/**********************************************************
*/

@Override
public final void flush() throws IOException
{
public final void flush() throws IOException {
_writer.flush(isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM));
}

Expand Down Expand Up @@ -416,34 +425,37 @@ public void writeString(String text) throws IOException,JsonGenerationException
return;
}
_verifyValueWrite("write String value");
_writer.write(_columnIndex(), text);
if (!_skipValue) {
_writer.write(_columnIndex(), text);
}
}

@Override
public void writeString(char[] text, int offset, int len) throws IOException, JsonGenerationException
{
_verifyValueWrite("write String value");
_writer.write(_columnIndex(), text, offset, len);
if (!_skipValue) {
_writer.write(_columnIndex(), text, offset, len);
}
}

@Override
public final void writeString(SerializableString sstr)
throws IOException, JsonGenerationException
public final void writeString(SerializableString sstr) throws IOException, JsonGenerationException
{
_verifyValueWrite("write String value");
_writer.write(_columnIndex(), sstr.getValue());
if (!_skipValue) {
_writer.write(_columnIndex(), sstr.getValue());
}
}

@Override
public void writeRawUTF8String(byte[] text, int offset, int len)
throws IOException, JsonGenerationException
public void writeRawUTF8String(byte[] text, int offset, int len) throws IOException, JsonGenerationException
{
_reportUnsupportedOperation();
}

@Override
public final void writeUTF8String(byte[] text, int offset, int len)
throws IOException, JsonGenerationException
public final void writeUTF8String(byte[] text, int offset, int len) throws IOException, JsonGenerationException
{
writeString(new String(text, offset, len, "UTF-8"));
}
Expand Down Expand Up @@ -503,12 +515,14 @@ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int l
return;
}
_verifyValueWrite("write Binary value");
// ok, better just Base64 encode as a String...
if (offset > 0 || (offset+len) != data.length) {
data = Arrays.copyOfRange(data, offset, offset+len);
if (!_skipValue) {
// ok, better just Base64 encode as a String...
if (offset > 0 || (offset+len) != data.length) {
data = Arrays.copyOfRange(data, offset, offset+len);
}
String encoded = b64variant.encode(data);
_writer.write(_columnIndex(), encoded);
}
String encoded = b64variant.encode(data);
_writer.write(_columnIndex(), encoded);
}

/*
Expand All @@ -521,21 +535,27 @@ public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int l
public void writeBoolean(boolean state) throws IOException, JsonGenerationException
{
_verifyValueWrite("write boolean value");
_writer.write(_columnIndex(), state);
if (!_skipValue) {
_writer.write(_columnIndex(), state);
}
}

@Override
public void writeNull() throws IOException, JsonGenerationException
{
_verifyValueWrite("write null value");
_writer.writeNull(_columnIndex());
if (!_skipValue) {
_writer.writeNull(_columnIndex());
}
}

@Override
public void writeNumber(int i) throws IOException, JsonGenerationException
{
_verifyValueWrite("write number");
_writer.write(_columnIndex(), i);
if (!_skipValue) {
_writer.write(_columnIndex(), i);
}
}

@Override
Expand All @@ -546,7 +566,9 @@ public void writeNumber(long l) throws IOException, JsonGenerationException
writeNumber((int) l);
return;
}
_verifyValueWrite("write number");
if (!_skipValue) {
_verifyValueWrite("write number");
}
_writer.write(_columnIndex(), l);
}

Expand All @@ -558,21 +580,27 @@ public void writeNumber(BigInteger v) throws IOException, JsonGenerationExceptio
return;
}
_verifyValueWrite("write number");
_writer.write(_columnIndex(), v.toString());
if (!_skipValue) {
_writer.write(_columnIndex(), v.toString());
}
}

@Override
public void writeNumber(double d) throws IOException, JsonGenerationException
{
_verifyValueWrite("write number");
_writer.write(_columnIndex(), d);
if (!_skipValue) {
_writer.write(_columnIndex(), d);
}
}

@Override
public void writeNumber(float f) throws IOException, JsonGenerationException
{
_verifyValueWrite("write number");
_writer.write(_columnIndex(), f);
if (!_skipValue) {
_writer.write(_columnIndex(), f);
}
}

@Override
Expand All @@ -583,20 +611,24 @@ public void writeNumber(BigDecimal dec) throws IOException, JsonGenerationExcept
return;
}
_verifyValueWrite("write number");
String str = isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN) ?
dec.toPlainString() : dec.toString();
_writer.write(_columnIndex(), str);
if (!_skipValue) {
String str = isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN) ?
dec.toPlainString() : dec.toString();
_writer.write(_columnIndex(), str);
}
}

@Override
public void writeNumber(String encodedValue) throws IOException,JsonGenerationException, UnsupportedOperationException
public void writeNumber(String encodedValue) throws IOException, JsonGenerationException, UnsupportedOperationException
{
if (encodedValue == null) {
writeNull();
return;
}
_verifyValueWrite("write number");
_writer.write(_columnIndex(), encodedValue);
if (!_skipValue) {
_writer.write(_columnIndex(), encodedValue);
}
}

/*
Expand All @@ -606,8 +638,7 @@ public void writeNumber(String encodedValue) throws IOException,JsonGenerationEx
*/

@Override
public void writeOmittedField(String fieldName)
throws IOException, JsonGenerationException
public void writeOmittedField(String fieldName) throws IOException
{
// basically combination of "writeFieldName()" and "writeNull()"
if (_writeContext.writeFieldName(fieldName) == JsonWriteContext.STATUS_EXPECT_VALUE) {
Expand All @@ -634,8 +665,7 @@ public void writeOmittedField(String fieldName)
*/

@Override
protected final void _verifyValueWrite(String typeMsg)
throws IOException, JsonGenerationException
protected final void _verifyValueWrite(String typeMsg) throws IOException
{
int status = _writeContext.writeValue();
if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
Expand Down Expand Up @@ -671,13 +701,13 @@ protected final int _columnIndex()
* will flush possibly buffered column values, append linefeed
* and reset state appropriately.
*/
protected void finishRow() throws IOException, JsonGenerationException
protected void finishRow() throws IOException
{
_writer.endRow();
_nextColumnByName = -1;
}

protected void _handleFirstLine() throws IOException, JsonGenerationException
protected void _handleFirstLine() throws IOException
{
_handleFirstLine = false;
if (_schema.useHeader()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.fasterxml.jackson.dataformat.csv;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.*;

public class GeneratorIgnoreUnknownTest extends ModuleTestBase
{
@JsonPropertyOrder({ "x", "y", "z" })
public static class Point {
public int x;
public Integer y;
public Integer z = 8;
}

/*
/**********************************************************
/* Test methods
/**********************************************************
*/

public void testSimpleIgnore() throws Exception
{
ObjectMapper mapper = mapperForCsv();
final CsvSchema schema = CsvSchema.builder()
.addColumn("x")
.addColumn("z")
.build();
ObjectWriter writer = mapper.writerWithType(Point.class)
.withSchema(schema)
.with(JsonGenerator.Feature.IGNORE_UNKNOWN);
String csv = writer.writeValueAsString(new Point());
assertNotNull(csv);
}
}
Loading

0 comments on commit c2c83f8

Please sign in to comment.