Déplacement d'une API d'import/export CSV dans nuiton-utils ?
Dans Wao, j'avais fait un système d'import export CSV basé sur un modèle, cela permettait : * De séparer les préoccupations en trois parties * Le code chargé la lecture/l'écriture d'un fichier CSV à partir du modèle et d'une collection. Via une lib ou non. * Le code décrivant un modèle (entêtes, colonnes obligatoires ou non) symétrique (import/export) ou non (seulement import/seulement export). * Le code décrivant la façon dont il font parser/valider/formatter la donnée pour une colonne. Avantages de l'implémentation dans son état actuel : * Utilisation transparente de la techno d'écriture de fichiers CSV (l'import est implémenté avec com.csvreader, l'export est fait une memory avec un code maison parce que c'est adapté pour Wao). On pourra très bien changé la lib ou faire du FS plutôt que du in-memory sans avoir à changer quoi que ce soit. * Validation : à l'import, on vérifie que tous les headers sont connus et que ceux obligatoires sont présents. Dans les parser/formatters utilisés dans le modèles, on peut jeter une exception : l'import remontera l'exception encapsulée avec la ligne, la colonne, la valeur qui pose problème * Réutilisabilité des parser/formatter dans plusieurs modèles (très utilisé dans Wao). * C'est rapide (je me souviens que sur un import de 150 lignes, il y avait 2 secondes de lectures/parsing/validation pour 40 secondes d'accès à la base) * Les modèles d'import/export garantissent la symétrie, c'est à dire qu'un fichier exporté via ce modèle aura forcément un format conforme si on essaye de l'importer par la suite. (Si on change une colonne à l'import en disant que le type n'est plus date mais date/heure, cela impact l'export qui exportera en date/heure) * Au début, le moteur d'import avant la validation pousse les entêtes au modèle, au cas où il faudrait faire un peu de détection pour adapter le modèle en conséquence (besoin dans Wao) Inconvénients * Bien que fonctionnelle, la gestion d'erreur est implémentée de façon calamiteuse, notamment parce que j'ai voulu me baser sur Iterator dont #next() a une signature sans exception. * Je voulais pouvoir faire de la composition de modèle pour l'export. Par exemple, si j'ai définit un ExportModel<Boat>, que j'ai un bean Captain, et que je veux faire un ExportModel<Captain>, l'export des capitaines aurait inclus toutes les colonnes de l'ExportModel<Boat> et à chaque ligne on aurait les informations du navire. Ça doit être jouable mais c'est pas fait. * Le design et le code globalement sont pas terribles. * Le système fonctionne bien si on a en, à l'import, une colonne dans le CSV = une propriété du bean. Si on a une même info éclatée dans deux colonnes (par exemple, le bean a une prop p de type Date, et dans le CSV, on a trois colonnes jour mois année) c'est la grosse merde. Cela est toutefois compensé par la possibilité de faire un ImportModel<MonBeanSpecifiqueCenséReprensentéUneLigneDeCSV> qui aura trois propriétés (jour, mois, année), aux développeurs de recopier ça par la suite dans le champs Date qui va bien. Cela fait des objets en plus... Assez parlé, le code : D'abord les parsers (import), formatter (export) et parser/formatter (import et export) : http://svn.forge.codelutin.com/svn/wao/trunk/wao-business/src/main/java/fr/i... Par exemple, pour une Company : http://svn.forge.codelutin.com/svn/wao/trunk/wao-business/src/main/java/fr/i... Au formattage, je retourne son nom, au parse, je cherche dans la collection des companies, celle qui a ce nom. Exception si aucune trouvée, l'utilisateur verra « Erreur à la ligne 12, colonne "SOCIETE". Il n'y a pas de société ayant pour nom 'Dudule' » Les modèles : http://svn.forge.codelutin.com/svn/wao/trunk/wao-business/src/main/java/fr/i... Le plus simple étant celui ci : http://svn.forge.codelutin.com/svn/wao/trunk/wao-business/src/main/java/fr/i... L'export : List<Boat> boats = dao.findAllByQuery(query); BoatImportExportModel model = new BoatImportExportModel(); Export<Boat> export = new Export<Boat>(model, boats); InputStream inputStream = export.startExport(); return inputStream; // le CSV L'import ressemble beaucoup, du code est nécessaire pour fournir au modèle les collections des différentes entités qu'il faudra potentiellement rattacher à l'entité importée. -- Brendan Le Ny <bleny@codelutin.com> Code Lutin Conseil & Développement Logiciel Libre +33 (0)2 40 50 29 28 http://codelutin.com
Le 11/08/2011 11:08, Brendan Le Ny a écrit :
Dans Wao, j'avais fait un système d'import export CSV basé sur un modèle, cela permettait : * De séparer les préoccupations en trois parties * Le code chargé la lecture/l'écriture d'un fichier CSV à partir du modèle et d'une collection. Via une lib ou non. * Le code décrivant un modèle (entêtes, colonnes obligatoires ou non) symétrique (import/export) ou non (seulement import/seulement export). * Le code décrivant la façon dont il font parser/valider/formatter la donnée pour une colonne.
J'ai regardé un peu, d'un point de vue utilisation de la lib et utilisateur final (erreurs avec ligne et colone), ça me semble très bien. Si tu penses que l'API est bien, moi je dit go for it. Plus c'est utilisé partout, plus le code derrière va être consolidé/corrigé/amélioré. Et si l'API est bien et qu'on s'aperçoit que le code derrière est si pourri que ça, tant pis, on changera le code... Jean -- Jean Couteau -- Code Lutin 44 Boulevard des Pas Enchantés 44230 Saint Sébastien sur Loire -- Tel : 02 40 50 29 28 Port : 06 68 07 29 29 Fax : 09 59 92 29 28
participants (2)
-
Brendan Le Ny -
Jean Couteau