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

Write out headers even if no data rows written #128

Closed
ansell opened this issue Aug 3, 2016 · 3 comments
Closed

Write out headers even if no data rows written #128

ansell opened this issue Aug 3, 2016 · 3 comments
Milestone

Comments

@ansell
Copy link
Contributor

ansell commented Aug 3, 2016

If a schema is setup for a CSV writer and headers are setup to be used, the headers should be written when the writer is closed even if no data rows have been written.

Currently (unless I am using the library incorrectly), the header line is not written out unless there is at least one data row written out. I am not sure if this is relevant here or in another issue tracker such as databind.

My test code that I have been using to verify is:

List<String> headers = Arrays.asList("TestHeader1", "TestHeader2");
List<List<String>> dataSource = Arrays.asList();
// Or alternatively,
// List<List<String>> dataSource = Arrays.asList(Arrays.asList("TestValue1", "TestValue2"));
java.io.Writer writer = new StringWriter();
CsvSchema.Builder builder = CsvSchema.builder();
for (String nextHeader : headers) {
    builder = builder.addColumn(nextHeader);
}
CsvSchema schema = builder.setUseHeader(true).build();
try(SequenceWriter csvWriter = new CsvMapper().writerWithDefaultPrettyPrinter().with(schema).forType(List.class).writeValues(writer);) {
    for(List<String> nextRow : dataSource) {
        csvWriter.write(nextRow);
    }
    // Check to see whether dataSource is empty 
    // and if so write a single empty list to trigger header output
    if(dataSource.isEmpty()) {
        csvWriter.write(Arrays.asList());
    }
}
System.out.println(writer.toString());

If dataSource contains a single row, there are two lines sent to the Writer, but if it contains zero rows (as happens sometimes), I would like one line to be sent to the writer. One way as shown above is to send an empty List if we know that nothing was sent, but it would be simpler to use if that check were done internally by Jackson if it fits within the architecture.

@cowtowncoder
Copy link
Member

This is the right place to report this. I agree in that it'd be better to force output; current behavior stems from writing of the headers being triggered by code that starts a new line (via JsonToken.START_OBJECT, I think), and not something that was designed.

The challenge is mostly that of figuring out what to use as a trigger instead: construction of a SequenceWriter (or underlying JsonGenerator) is not enough due to some problems with setup (that is, figuring when everything is completely ready). One possibility would be ensure header has been written when CsvGenerator.close() gets called; that might be a reasonable way.

cowtowncoder added a commit that referenced this issue Aug 25, 2016
Fix issue #128 headers are not written if no rows are written
@cowtowncoder cowtowncoder added this to the 2.7.7 milestone Aug 25, 2016
cowtowncoder added a commit that referenced this issue Aug 25, 2016
@lukas0krupa
Copy link

I am using 2.8.1 and it seems to be an issue (unless I am doing something wrong). If stream is empty, I got empty file - no headers.

   private void saveData(
            final Supplier<OutputStream> responseOutputSupplier,
            final Stream<List<String>> lines) {
        try (final OutputStreamWriter osw = new OutputStreamWriter(responseOutputSupplier.get(), StandardCharsets.ISO_8859_1);
             final SequenceWriter sequenceWriter = MAPPER.writer(csvSchema()).writeValues(osw)) {
            lines.forEach(line -> {
                try {
                    sequenceWriter.write(line);
                } catch (IOException e) {
                    log.error("Unable to write to the file", e);
                }
            });
            sequenceWriter.writeAll(emptyList());
        } catch (IOException e) {
            log.error("Unable to write to the file", e);
        }
   }

   private CsvSchema csvSchema() {
        final CsvSchema.Builder builder = new CsvSchema.Builder();
        builder.setUseHeader(true);
        builder.addColumn("column1");
        builder.addColumn("column2");
        return builder.build();
   }

@cowtowncoder
Copy link
Member

@lukas0krupa Make sure to use a later version, 2.8.3. We keep multiple branches open, so 2.7.7 was actually released after 2.8.1, so fix has gone in either 2.8.2 or 2.8.3.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants