Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,15 @@ private Feature(boolean defaultState) {
*/
protected boolean _skipValue;

/**
* Flag set when a row has just been finished, used to distinguish between
* null values within a row vs null rows.
* Only relevant for Array-wrapped rows.
*
* @since 2.21
*/
protected boolean _justFinishedRow = false;

/**
* Separator to use during writing of (simple) array value, to be encoded as a
* single column value, if any.
Expand Down Expand Up @@ -562,6 +571,7 @@ public void close() throws IOException
public final void writeStartArray() throws IOException
{
_verifyValueWrite("start an array");
_justFinishedRow = false; // Clear flag when starting new array
// Ok to create root-level array to contain Objects/Arrays, but
// can not nest arrays in objects
if (_tokenWriteContext.inObject()) {
Expand Down Expand Up @@ -636,6 +646,8 @@ public final void writeEndArray() throws IOException
public final void writeStartObject() throws IOException
{
_verifyValueWrite("start an object");
_justFinishedRow = false;

// 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 (_tokenWriteContext.inObject() ||
Expand Down Expand Up @@ -882,7 +894,12 @@ public void writeNull() throws IOException
// 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 (!_tokenWriteContext.getParent().inRoot()) {
// [dataformats-text#10]: When we have a schema and we haven't just finished a row,
// it means we're inside an array-as-row (like Object[]), so null is a column value
boolean writeNullValue = !_tokenWriteContext.getParent().inRoot()
|| (_schema.size() > 0 && !_justFinishedRow);

if (writeNullValue) {
// 26-Aug-2024, tatu: [dataformats-text#495] Decorations?
if (_nextColumnDecorator != null) {
String nvl = _nextColumnDecorator.decorateNull(this);
Expand Down Expand Up @@ -1132,6 +1149,7 @@ protected void finishRow() throws IOException
{
_writer.endRow();
_nextColumnByName = -1;
_justFinishedRow = true;
}

protected void _handleFirstLine() throws IOException
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.dataformat.csv.tofix;
package com.fasterxml.jackson.dataformat.csv.ser;

import java.io.StringWriter;

Expand All @@ -7,16 +7,12 @@
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SequenceWriter;
import com.fasterxml.jackson.dataformat.csv.*;
import com.fasterxml.jackson.dataformat.csv.testutil.failure.JacksonTestFailureExpected;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class MissingNullsOnObjectArrayWrite10Test extends ModuleTestBase
public class ObjectArrayNullWrite10Test extends ModuleTestBase
{
private final CsvMapper MAPPER = mapperForCsv();

// for [dataformats-text#10]
@JacksonTestFailureExpected
@Test
public void testNullsOnObjectArrayWrites2Col() throws Exception
{
Expand All @@ -25,13 +21,14 @@ public void testNullsOnObjectArrayWrites2Col() throws Exception
.addColumn("b", CsvSchema.ColumnType.NUMBER)
.setUseHeader(true)
.build();
ObjectWriter writer = MAPPER.writer(schema);
ObjectWriter writer = mapperForCsv().writer(schema);
StringWriter out = new StringWriter();
SequenceWriter sequence = writer.writeValues(out);

sequence.write(new Object[]{ null, 2 });
sequence.write(new Object[]{ null, null });
sequence.write(new Object[]{ 1, null });
try (SequenceWriter sequence = writer.writeValues(out)) {
sequence.write(new Object[]{ null, 2 });
sequence.write(new Object[]{ null, null });
sequence.write(new Object[]{ 1, null });
}

final String csv = out.toString().trim();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.fasterxml.jackson.dataformat.csv.tofix;
package com.fasterxml.jackson.dataformat.csv.ser;

import java.io.StringWriter;

Expand All @@ -7,41 +7,34 @@
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SequenceWriter;
import com.fasterxml.jackson.dataformat.csv.*;
import com.fasterxml.jackson.dataformat.csv.testutil.failure.JacksonTestFailureExpected;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class NullWriting116Test extends ModuleTestBase
public class ObjectArrayNullWrite116Test extends ModuleTestBase
{
private final CsvMapper csv = mapperForCsv();

// [dataformat#116]
@JacksonTestFailureExpected
// for [dataformats-text#116]
@Test
public void testWithObjectArray() throws Exception
public void testWithObjectArray() throws Exception
{
CsvSchema schema = CsvSchema.builder()
.addColumn("a", CsvSchema.ColumnType.NUMBER)
.addColumn("b", CsvSchema.ColumnType.NUMBER)
.setUseHeader(true)
.build();
ObjectWriter writer = csv.writer(schema);
ObjectWriter writer = mapperForCsv().writer(schema);
StringWriter out = new StringWriter();
SequenceWriter sequence = writer.writeValues(out);

sequence.write(new Object[]{ 1, 2 });
// sequence.write(new Object[]{ null, 2 });
sequence.write(new Object[]{ null, null });
sequence.write(new Object[]{ 1, null });

sequence.close();
try (SequenceWriter sequence = writer.writeValues(out)) {
sequence.write(new Object[]{ 1, 2 });
sequence.write(new Object[]{ null, 2 });
sequence.write(new Object[]{ null, null });
sequence.write(new Object[]{ 1, null });
}

//System.err.println("CSV:\n"+out);
assertEquals("a,b\n" +
"1,2\n" +
// ",2\n" +
",2\n" +
",\n" +
"1,\n", out.toString());
}

}
3 changes: 2 additions & 1 deletion release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ Active Maintainers:

2.21.0 (not yet released)

No changes since 2.20
#10: Missing `null` writes when writing `Object[]` values
(fix by @cowtowncoder, w/ Claude code)

2.20.1 (30-Oct-2025)

Expand Down