Salut, J'ai continué les TU sur nuiton-csv, et notamment tester le ModelBuilder. Mais j'ai un doute de son utilité. En gardant l'idée de l'api, j'ai fais une implem un peu plus pousser avec une methode buildImportModel qui te renvoie directement un ImportModel avec les différentes colonnes construites. Finalement il serait plus simple que le ModelBuilder implémente les deux interfaces ImportModel et ExportModel, on pourrait le renommer en CsvModel. Pour les besoins spécifiques rien n'empêchera l'héritage. Ainsi pushCsvHeaderNames sera vide par défaut et étendu au besoin (d'ailleurs je la renommerais bien en onReadHeaders pour montrer son côté callback). Même chose pour le newInstance, en passant la classe au constructeur du modèle, on peut proposer une implem par défaut avec un myClass.newInstance. Libre à l'utilisateur de surcharger s'il veut un comportement plus pousser (utiliser sa propre factory). Une autre idée serait de proposer des contrats pour avoir un callback sur les headers et une factory pour l'instanciation. Je reviens aussi sur les interfaces ImportableColumn et ExportableColumn que je trouve inutiles. Il faut juste permettre le !mandatory & !ignored dans la classe Column. Pour l'Import je rajouterais bien aussi des méthodes qui l’exécute directement sans avoir besoin d'instance d'Import. Par exemple : public static <E> List<E> getResultAsList(ImportModel<E> model, Reader reader) { Import<E> instance = Import.newImport(model, reader); try { List<E> result = new ArrayList<E>(); for (E row : instance) { result.add(row); } return result; } finally { instance.close(); } } En pratique on pourrait avoir : CsvModel<Row> model = CsvModel.newModel(';', Row.class); model.addMandatoryColumn("TITLE", "title"); model.addMandatoryColumn("DATE", "date", new Common.DateValue("yyyy-MM-dd")); model.addMandatoryColumn("NUMBER", "number", Common.INTEGER); List<Row> results = Import.getResultAsList(model, reader); Qu'en pensez-vous ? je vais maintenant regarder l'Export voir si ça se goupille bien. Je pense qu'on peut avoir une api bien sympa en tout cas, mais ya encore pas mal de chose à voir pour simplifier/fignoler. --------------8<----------------8<--------------8<----------------- Exemple plus compliqué comme dans WAO : CSV: --- TITLE;01/2010;02/2010;03/2010 "Row1";1;2;3 "Row2";5;0;1 "Row3";4;1;0 Import: --- CsvModel<Row> builder = CsvModel.newModel(';', Row.class); builder.addMandatoryColumn("TITLE", "title"); builder.setHeadersCallback(new CsvModel.HeadersCallback() { @Override public void onReadHeaders(List<String> headerNames) { List<String> dynamicHeaders = headerNames.subList(1, headerNames.size()); for (String header : dynamicHeaders) { // Format header to have Date value Date month; try { month = DateUtils.parseDate(header, "MM/yyyy"); } catch (ParseException e) { throw new ImportRuntimeException("Parsing error of dynamic header " + header, e); } // Add the dynamic column using Row specified setter builder.addMandatoryColumn( header, Common.INTEGER, Row.getMonthValueSetter(month) ); } } }); List<Row> results = Import.getResultAsList(model, reader); Row : --- public class Row { private String title; private SortedMap<Date, Integer> monthValues; public Row() { this.monthValues = new TreeMap<Date, Integer>(); } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public void addMonth(Date month, Integer value) { monthValues.put(month, value); } public Map<Date, Integer> getMonthValues() { return monthValues; } public static ValueSetter<Row, Integer> getMonthValueSetter(final Date month) { return new ValueSetter<Row, Integer>() { @Override public void set(Row object, Integer value) throws Exception { object.addMonth(month, value); } }; } }