Skip to content

Commit

Permalink
Start piecing together changes for #97
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Nov 26, 2019
1 parent 2bfeb11 commit 357039b
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.fasterxml.jackson.core.json.JsonWriteContext;
import com.fasterxml.jackson.core.io.IOContext;
import com.fasterxml.jackson.dataformat.csv.impl.CsvEncoder;
import com.fasterxml.jackson.dataformat.csv.impl.SimpleTokenWriteContext;

public class CsvGenerator extends GeneratorBase
{
Expand Down Expand Up @@ -159,6 +160,14 @@ private Feature(boolean defaultState) {
// note: can not be final since we may need to re-create it for new schema
protected CsvEncoder _writer;

/**
* Current context, in form we can use it (GeneratorBase has
* untyped reference; left as null)
*
* @since 2.11
*/
protected SimpleTokenWriteContext _csvWriteContext;

protected CharacterEscapes _characterEscapes = null;

/*
Expand Down Expand Up @@ -216,7 +225,7 @@ private Feature(boolean defaultState) {
*
* @since 2.7
*/
protected JsonWriteContext _skipWithin;
protected SimpleTokenWriteContext _skipWithin;

/*
/**********************************************************
Expand All @@ -235,7 +244,7 @@ public CsvGenerator(IOContext ctxt, int jsonFeatures, int csvFeatures,
_formatFeatures = csvFeatures;
_schema = schema;
_writer = new CsvEncoder(ctxt, csvFeatures, out, schema);

_csvWriteContext = SimpleTokenWriteContext.createRootContext(null);
_writer.setOutputEscapes(CsvCharacterEscapes.fromCsvFeatures(csvFeatures).getEscapeCodesForAscii());
}

Expand All @@ -246,6 +255,7 @@ public CsvGenerator(IOContext ctxt, int jsonFeatures, int csvFeatures,
_ioContext = ctxt;
_formatFeatures = csvFeatures;
_writer = csvWriter;
_csvWriteContext = SimpleTokenWriteContext.createRootContext(null);
}

/*
Expand Down Expand Up @@ -298,6 +308,11 @@ public int getOutputBuffered() {
return _writer.getOutputBuffered();
}

@Override
public SimpleTokenWriteContext getOutputContext() {
return _csvWriteContext;
}

@Override
public void setSchema(FormatSchema schema)
{
Expand Down Expand Up @@ -380,7 +395,7 @@ public boolean canOmitFields() {
@Override
public final void writeFieldName(String name) throws IOException
{
if (_writeContext.writeFieldName(name) == JsonWriteContext.STATUS_EXPECT_VALUE) {
if (!_csvWriteContext.writeFieldName(name)) {
_reportError("Can not write a field name, expecting a value");
}
_writeFieldName(name);
Expand All @@ -390,7 +405,7 @@ public final void writeFieldName(String name) throws IOException
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) {
if (!_csvWriteContext.writeFieldName(name.getValue())) {
_reportError("Can not write a field name, expecting a value");
}
_writeFieldName(name.getValue());
Expand Down Expand Up @@ -492,10 +507,10 @@ public final void writeStartArray() throws IOException
_verifyValueWrite("start an array");
// Ok to create root-level array to contain Objects/Arrays, but
// can not nest arrays in objects
if (_writeContext.inObject()) {
if (_csvWriteContext.inObject()) {
if ((_skipWithin == null)
&& _skipValue && isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
_skipWithin = _writeContext;
_skipWithin = _csvWriteContext;
} else if (!_skipValue) {
// First: column may have its own separator
String sep;
Expand Down Expand Up @@ -525,20 +540,20 @@ && _skipValue && isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
_reportError("CSV generator does not support nested Array values");
}
}
_writeContext = _writeContext.createChildArrayContext();
_csvWriteContext = _csvWriteContext.createChildArrayContext(null);
// and that's about it, really
}

@Override
public final void writeEndArray() throws IOException
{
if (!_writeContext.inArray()) {
_reportError("Current context not Array but "+_writeContext.typeDesc());
if (!_csvWriteContext.inArray()) {
_reportError("Current context not Array but "+_csvWriteContext.typeDesc());
}
_writeContext = _writeContext.getParent();
_csvWriteContext = _csvWriteContext.getParent();
// 14-Dec-2015, tatu: To complete skipping of ignored structured value, need this:
if (_skipWithin != null) {
if (_writeContext == _skipWithin) {
if (_csvWriteContext == _skipWithin) {
_skipWithin = null;
}
return;
Expand All @@ -549,7 +564,7 @@ public final void writeEndArray() throws IOException
}
// 20-Nov-2014, tatu: When doing "untyped"/"raw" output, this means that row
// is now done. But not if writing such an array field, so:
if (!_writeContext.inObject()) {
if (!_csvWriteContext.inObject()) {
finishRow();
}
}
Expand All @@ -560,30 +575,30 @@ public final void writeStartObject() throws IOException
_verifyValueWrite("start an object");
// No nesting for objects; can write Objects inside logical root-level arrays.
// 14-Dec-2015, tatu: ... except, should be fine if we are ignoring the property
if (_writeContext.inObject() ||
if (_csvWriteContext.inObject() ||
// 07-Nov-2017, tatu: But we may actually be nested indirectly; so check
(_writeContext.inArray() && !_writeContext.getParent().inRoot())) {
(_csvWriteContext.inArray() && !_csvWriteContext.getParent().inRoot())) {
if (_skipWithin == null) { // new in 2.7
if (_skipValue && isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
_skipWithin = _writeContext;
_skipWithin = _csvWriteContext;
} else {
_reportMappingError("CSV generator does not support Object values for properties (nested Objects)");
}
}
}
_writeContext = _writeContext.createChildObjectContext();
_csvWriteContext = _csvWriteContext.createChildObjectContext(null);
}

@Override
public final void writeEndObject() throws IOException
{
if (!_writeContext.inObject()) {
_reportError("Current context not Object but "+_writeContext.typeDesc());
if (!_csvWriteContext.inObject()) {
_reportError("Current context not Object but "+_csvWriteContext.typeDesc());
}
_writeContext = _writeContext.getParent();
_csvWriteContext = _csvWriteContext.getParent();
// 14-Dec-2015, tatu: To complete skipping of ignored structured value, need this:
if (_skipWithin != null) {
if (_writeContext == _skipWithin) {
if (_csvWriteContext == _skipWithin) {
_skipWithin = null;
}
return;
Expand Down Expand Up @@ -760,16 +775,16 @@ public void writeNull() throws IOException
if (!_skipValue) {
if (!_arraySeparator.isEmpty()) {
_addToArray(_schema.getNullValueOrEmpty());
} else if (_writeContext.inObject()) {
} else if (_csvWriteContext.inObject()) {
_writer.writeNull(_columnIndex());
} else if (_writeContext.inArray()) {
} else if (_csvWriteContext.inArray()) {
// [dataformat-csv#106]: Need to make sure we don't swallow nulls in arrays either
// 04-Jan-2016, tatu: but check for case of array-wrapping, in which case null stands for absence
// of Object. In this case, could either add an empty row, or skip -- for now, we'll
// just skip; can change, if so desired, to expose "root null" as empty rows, possibly
// based on either schema property, or CsvGenerator.Feature.
// Note: if nulls are to be written that way, would need to call `finishRow()` right after `writeNull()`
if (!_writeContext.getParent().inRoot()) {
if (!_csvWriteContext.getParent().inRoot()) {
_writer.writeNull(_columnIndex());
}

Expand Down Expand Up @@ -909,7 +924,7 @@ public void writeOmittedField(String fieldName) throws IOException
// assumed to have been removed from schema too
} else {
// basically combination of "writeFieldName()" and "writeNull()"
if (_writeContext.writeFieldName(fieldName) == JsonWriteContext.STATUS_EXPECT_VALUE) {
if (!_csvWriteContext.writeFieldName(fieldName)) {
_reportError("Can not skip a field, expecting a value");
}
// and all we do is just note index to use for following value write
Expand All @@ -929,8 +944,7 @@ public void writeOmittedField(String fieldName) throws IOException
@Override
protected final void _verifyValueWrite(String typeMsg) throws IOException
{
int status = _writeContext.writeValue();
if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
if (!_csvWriteContext.writeValue()) {
_reportError("Can not "+typeMsg+", expecting field name");
}
if (_handleFirstLine) {
Expand Down
Loading

0 comments on commit 357039b

Please sign in to comment.