SimpleFlatMapper
SimpleFlatMapper copied to clipboard
[Question] Generate dynamic header
Hi, there!
Is there a possibility to map a dynamic number of columns from a CSV to a list?
The only solution that I have found is to generate the headers dynamically depending on what I need but I don't know if there is a better solution.
Here an example of what I'm trying to do:
@Test
public void testCsvParser() throws Exception {
String csv = new StringBuilder()
.append("StarWarsI~!~2~!~R2-D2~!~R2-D2" + System.lineSeparator())
.append("StarWarsII~!~3~!~R2-D2" + System.lineSeparator())
.append("StarWarsIII~!~4~!~R2-D2~!~R2-D2~!~R2-D2~!~R2-D2~!~R2-D2" + System.lineSeparator())
.append("StarWarsIV~!~5~!~R2-D2~!~R2-D2~!~R2-D2~!~R2-D2" + System.lineSeparator())
.append("StarWarsV~!~6~!~R2-D2~!~R2-D2~!~R2-D2" + System.lineSeparator())
.toString();
List<Film> films = new ArrayList<>();
Arrays.stream(csv.split(System.lineSeparator())).forEach( line -> {
line = line.replaceAll("~!~", ",");
try {
String[] headers = {"name", "id"};
headers = this.generateDynamicHeaders(headers, line, 2);
Film film = CsvParser
.mapTo(Film.class)
.headers(headers)
.stream(line)
.findFirst()
.get();
films.add(film);
} catch (IOException e) {
e.printStackTrace();
}
});
films.forEach(System.out::println);
}
private String[] generateDynamicHeaders(String[] currentHeaders, String line, int startIndex) {
List<String> headers = Arrays.stream(currentHeaders).collect(Collectors.toList());
List<String> lineAsList = Arrays.stream(line.split(",")).collect(Collectors.toList());
for (int i = 0; i < lineAsList.size() - startIndex; i++) {
headers.add("actors_" + i + "_name");
}
return headers.toArray(new String[headers.size()]);
}
public static class Film {
private String name;
private int id;
private List<Actor> actors;
public Film(int id, String name, List<Actor> actors) {
this.id = id;
this.name = name;
this.actors = actors == null ? new ArrayList<>() : actors;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public List<Actor> getActors() {
return actors;
}
@Override
public String toString() {
return "Film{ id='" + id + "\' name='" + name + "\' actors=" + actors.toString() + " }";
}
}
public static class Actor{
private String name;
public Actor(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Actor{ name='" + name + "\'}";
}
}
Thanks a lot!
there is a strategy to generate default headers but it does not support list as it can't know the size of the list in advance. there is also 2 ways of dealing with list. it's not currently very developped
also made me realized the separator question was related tothe writer? in that case it would be quite straightforward to change it to accept strings