Search code examples
javacsvsimpleflatmapper

How to alias prefixed CSV columns to a Map with SimpleFlatMapper?


Background

Using SimpleFlatMapper sfm-csv 6.0.3

Example CSV:

|------|-------------|----------------|----------------|------------------|
| name | reference # | pf.first thing | pf.secondThing | pf.another.thing |
|======|=============|================|================|==================|
| foo  | eb2e23c0d6a | a value here   |                | another value    |
|------|-------------|----------------|----------------|------------------|
| bar  | 0a4bba4c1d0 | values         | all            | throughout       |
|------|-------------|----------------|----------------|------------------|

Pojo

class Item {

    private String name;
    private String reference;
    private Map<String, String> prefixedFields;

    // ... builder, getters, etc.

}

Simplified code

final CsvMapper<Item> mapper = CsvMapperFactory.newInstance()
    .addAlias("name", "itemName")
    .addAlias("reference #", "reference")
    .newMapper(Item.class);

return CsvParser.mapWith(mapper)
    .stream(file, items -> items.collect(List.collector()));

Problem

As is, the Map is coming back null. I'm trying to get to a point where:

firstRowItem.getPrefixedFields() == ImmutableMap.of(
    "first thing", "a value here",
    "another.thing", "another value")

secondRowItem.getPrefixedFields() == ImmutableMap.of(
    "first thing", "values",
    "secondThing", "all",
    "another.thing", "throughout")

The "pf." prefix is set in stone, and everything works if the property is named "pf":

class Item {
    // ...
    private Map<String, String> pf;
    // ...
}

but I'd like for the property to be named "prefixedFields" instead of "pf".

Attempts at resolution

.addColumnProperty(
    col -> col.getName().startsWith("pf."),
    MapTypeProperty.KEY_VALUE)
  • .addAlias only accepts String params, so something like this doesn't work:
.addAlias("pf.", "prefixedFields")

Solution

  • A comment on a GitHub issue from the project owner got me on the right track.

    addColumnProperty accepts varargs of Object. You can pass in a RenameProperty, which accepts either a String param for simple column renaming or a Function<String, String> renameFunction. Put those together like so:

    final CsvMapper<Item> mapper = CsvMapperFactory.newInstance()
        .addAlias("name", "itemName")
        .addAlias("reference #", "reference")
        .addColumnProperty(
            column -> column.getName().startsWith("pf."),
            new RenameProperty(columnName -> columnName.replace("pf.", "prefixedFields_")))
        .newMapper(Item.class);