jackson-dataformats-text icon indicating copy to clipboard operation
jackson-dataformats-text copied to clipboard

MappingIterator returns List or Map depending on CSVSchema.withHeader

Open flappingeagle opened this issue 6 years ago • 4 comments

If CSVSchema.withHeader == true i must do:

final Map<String, String> line = (Map<String, String>) mappingIterator.nextValue();

If CSVSchema.withHeader == false i must do:

final List<String> line = (List<String>) mappingIterator.nextValue();

My use-case is: I have only one Class in which i parse CSV and this class can be configured to read the csv with header or without header (boolean-flag). For me it would be better if the MappingIterator always returns the same result-type (either a list or a map). Its not necessary, but would make things easier for me because now i need to cast the type like above, which looks a bit unsafe and is marked as yellow-warning in Eclipse-IDE.

flappingeagle avatar May 28 '18 08:05 flappingeagle

I would need a full unit test (or just complete code for usage) to make sure I understand this. Behavior should not vary, regardless of whether header line exists, so I agree in that you should not have to change code there.

cowtowncoder avatar May 29 '18 23:05 cowtowncoder

ok, here you go:

        // configure test --> set to true/false to test.
        final boolean withHeader = true;
        
        // prepare test-value
        final String s = "a;b;c;d;e\n1;2;3;4;5";
        final InputStream is = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));

        // lets go...
        CsvSchema schema = CsvSchema.emptySchema()
                .withColumnSeparator(';')
                .withLineSeparator("\n")
                .withQuoteChar('"');

        final ObjectReader reader;
        if (withHeader) {
            schema = schema.withHeader();
            reader = new CsvMapper().readerFor(Map.class).with(schema);
        } else {
            schema = schema.withoutHeader();
            reader = new CsvMapper().enable(CsvParser.Feature.WRAP_AS_ARRAY)
                    .readerFor(List.class).with(schema);
        }

        final MappingIterator<?> mappingIterator = reader.readValues(is);

        final Object result = mappingIterator.next();
        System.out.println(result);
        System.out.println(result.getClass()); 

You can experiment by changing the readerFor(List.class) to a readerFor(Map.class) and see that it will not work. So currently its only possible to use readerFor(List.class) for the schema.withoutHeader(). Otherwise it will not run.

flappingeagle avatar May 30 '18 08:05 flappingeagle

@cowtowncoder the commit that closed this issue seems unrelated - I ran the OP's test case and the 'issue' still exists - there is an argument that this should still be closed as 'works as expected'

pjfanning avatar Jun 26 '22 10:06 pjfanning

@pjfanning Yes, I must have accidentally referred to the wrong issue on commit.

cowtowncoder avatar Jun 26 '22 19:06 cowtowncoder