Author: tchemit Date: 2011-11-30 18:12:49 +0100 (Wed, 30 Nov 2011) New Revision: 2244 Url: http://nuiton.org/repositories/revision/nuiton-utils/2244 Log: - improve the Import design - introduce a ImportMap to import into a map (usefull when there is no direct bean for each line of a csv import) Added: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/ImportToMap.java Modified: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Common.java trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_en_GB.properties trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_es_ES.properties trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_fr_FR.properties trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java trunk/nuiton-csv/src/test/resources/org/nuiton/util/csv/importTest.csv Modified: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Common.java =================================================================== --- trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Common.java 2011-11-30 09:00:26 UTC (rev 2243) +++ trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Common.java 2011-11-30 17:12:49 UTC (rev 2244) @@ -50,7 +50,7 @@ public static final ValueParserFormatter<String> STRING = new StringValueParser(); - + public static final ValueFormatter<?> TO_STRING_FORMATTER = new ToStringValueFormatter(); @@ -100,6 +100,14 @@ public static final ValueParserFormatter<Date> WEEK = new DateValue("w/yyyy"); + public static <E extends Map<String, Object>, T> MapProperty<E, T> newMapProperty(String propertyName) { + return new MapProperty<E, T>(propertyName); + } + + public static <E , T> BeanProperty<E, T> newBeanProperty(String propertyName) { + return new BeanProperty<E, T>(propertyName); + } + public static class StringValueParser implements ValueParserFormatter<String> { @Override @@ -117,7 +125,7 @@ @Override public String format(Object value) { - return value==null?"":value.toString(); + return value == null ? "" : value.toString(); } } @@ -141,6 +149,26 @@ } } + public static class MapProperty<E extends Map<String, Object>, T> implements ValueGetterSetter<E, T> { + + protected String propertyName; + + MapProperty(String propertyName) { + this.propertyName = propertyName; + } + + @Override + public void set(E bean, T value) throws Exception { + bean.put(propertyName, value); + } + + @Override + public T get(E object) throws Exception { + T value = (T) object.get(propertyName); + return value; + } + } + public static class DateValue implements ValueParserFormatter<Date> { protected DateFormat dateFormat; Modified: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java =================================================================== --- trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java 2011-11-30 09:00:26 UTC (rev 2243) +++ trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/Import.java 2011-11-30 17:12:49 UTC (rev 2244) @@ -24,6 +24,12 @@ */ package org.nuiton.util.csv; +import com.csvreader.CsvReader; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.util.StringUtil; + +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.Reader; @@ -38,31 +44,40 @@ import java.util.NoSuchElementException; import java.util.Set; -import com.csvreader.CsvReader; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.nuiton.util.StringUtil; - import static org.nuiton.i18n.I18n._; /** - * TODO + * Import engine for a given import model. * + * It acts as an {@link Iterable}, you can use directly inside a foreach. + * + * The method {@link #prepareAndValidate()} will be invoked before all and + * only once. It mainly obtain header from the csv input, pass it to the model + * and then validate the model. + * * @author bleny <leny@codelutin.com> * @author tchemit <chemit@codelutin.com> + * @author fdesbois <desbois@codelutin.com> * @since 2.4 */ -public class Import<E> implements Iterable<E> { +public class Import<E> implements Iterable<E>, Closeable { /** Logger. */ private static final Log log = LogFactory.getLog(Import.class); + /** Csv import model. */ protected ImportModel<E> model; + /** Csv reader (this is the input). */ protected CsvReader reader; - /** save once done to prevent multiple headers read leading to consider first lines as headers */ - protected ValidationResult csvValidationResult; + /** + * A flag to know if model was already validated. + * <p/> + * Save once done to prevent multiple headers read leading to consider + * first lines as headers. + */ + protected boolean validate; public static <E> Import<E> newImport(ImportModel<E> model, InputStream inputStream) { @@ -74,87 +89,13 @@ return new Import<E>(model, reader); } - public ValidationResult validateCsv() throws IOException { + @Override + public Iterator<E> iterator() { - if (csvValidationResult == null) { + prepareAndValidate(); - boolean canReadHeaders = reader.readHeaders(); - if (!canReadHeaders) { - throw new IOException("can't read headers"); - } + readFirstLine(); - if (log.isTraceEnabled()) { - log.trace("headers of the CSV file are : " + Arrays.toString(reader.getHeaders())); - } - - model.pushCsvHeaderNames(Arrays.asList(reader.getHeaders())); - - validateModel(); - - csvValidationResult = new ValidationResult(); - csvValidationResult.setSuccess(true); - - List<String> csvHeaders = new ArrayList<String>(); - Collections.addAll(csvHeaders, reader.getHeaders()); - - for (ImportableColumn<E, ?> field : model.getColumnsForImport()) { - csvHeaders.remove(field.getHeaderName()); - } - - if (!csvHeaders.isEmpty()) { - csvValidationResult.setSuccess(false); - List<String> validHeaderNames = new LinkedList<String>(); - for (ImportableColumn<E, ?> importableColumn : model.getColumnsForImport()) { - validHeaderNames.add(importableColumn.getHeaderName()); - } - String validationMessage = _( - "csv.import.error.unrecognizedHeaders", - StringUtil.join(csvHeaders, ", ", true), - StringUtil.join(validHeaderNames, ", ", true)); - csvValidationResult.setMessage(validationMessage); - } - - csvHeaders = new ArrayList<String>(); - Collections.addAll(csvHeaders, reader.getHeaders()); - - List<String> mandatoryHeadersNames = new ArrayList<String>(); - for (ImportableColumn<E, ?> field : getAllMandatoryHeaders()) { - mandatoryHeadersNames.add(field.getHeaderName()); - } - mandatoryHeadersNames.removeAll(csvHeaders); - - if (!mandatoryHeadersNames.isEmpty()) { - csvValidationResult.setSuccess(false); - String validationMessage = _( - "csv.import.error.missingMandatoryHeaders", - StringUtil.join(mandatoryHeadersNames, ", ", true)); - csvValidationResult.setMessage(validationMessage); - } - } - - return csvValidationResult; - } - - public Iterator<E> startImport() throws IOException { - validateHeaders(); - Iterator<E> result = iterator(); - return result; - } - - public void validateHeaders() - throws IOException { - - ValidationResult validationResult = validateCsv(); - - if (!validationResult.isSuccess()) { - throw new IOException(validationResult.getMessage()); - } - } - - @Override - public Iterator<E> iterator() { - // XXX-fdesbois-2011-11-28 : it will be better to have a flag in ImportModel to know if headers are present or not - readFirstLine(); return new Iterator<E>() { boolean hasNext = true; @@ -188,7 +129,9 @@ value = reader.get(field.getHeaderName()); } catch (Exception e) { reader.close(); - throw new ImportRuntimeException(_("csv.import.error.unableToReadField", field.getHeaderName(), lineNumber), e); + throw new ImportRuntimeException( + _("csv.import.error.unableToReadField", + field.getHeaderName(), lineNumber), e); } // contravariance ftw @@ -196,8 +139,9 @@ try { parsedValue = field.parseValue(value); } catch (Exception e) { - String message = _("csv.import.error.unableToParseValue", value, field.getHeaderName(), lineNumber) - + "\n" + e.getMessage(); + String message = _("csv.import.error.unableToParseValue", + value, field.getHeaderName(), lineNumber) + + "\n" + e.getMessage(); throw new ImportRuntimeException(message, e); } @@ -206,9 +150,9 @@ field.setValue(element, parsedValue); } catch (Exception e) { String message = _("csv.import.error.unableToSetValue", - parsedValue, - element.toString(), - lineNumber, field.getHeaderName()); + parsedValue, + element.toString(), + lineNumber, field.getHeaderName()); if (log.isErrorEnabled()) { log.error(message); } @@ -223,7 +167,8 @@ } catch (IOException e) { reader.close(); throw new ImportRuntimeException( - _("csv.import.error.unableToReadLine", lineNumber + 1), e); + _("csv.import.error.unableToReadLine", + lineNumber + 1), e); } return lastElement; @@ -233,14 +178,135 @@ public void remove() { throw new UnsupportedOperationException(); } - }; } - public void stopImport() { + @Override + public void close() { reader.close(); } + public void prepareAndValidate() { + + if (validate) { + + // was already validated + return; + } + + // mark as validated + validate = true; + + // obtains headers + String[] headers = getHeaders(); + + if (log.isTraceEnabled()) { + log.trace("headers of the CSV file are : " + + Arrays.toString(headers)); + } + + // hook to do some stuff from the model + model.pushCsvHeaderNames(Arrays.asList(headers)); + + // check model columns name are unique + checkUniqueModelColumnNames(); + + // check that given headers from csv file are all known + + checkHeaderNamesAreAllKnown(headers); + + // check all mandatories column are on csv header + checkAllManadatoryHeadersArePresent(headers); + } + + protected void checkHeaderNamesAreAllKnown(String[] headers) { + List<String> csvHeaders = new ArrayList<String>(); + Collections.addAll(csvHeaders, headers); + + for (ImportableColumn<E, ?> field : model.getColumnsForImport()) { + csvHeaders.remove(field.getHeaderName()); + } + if (!csvHeaders.isEmpty()) { + List<String> validHeaderNames = new LinkedList<String>(); + for (ImportableColumn<E, ?> importableColumn : + model.getColumnsForImport()) { + validHeaderNames.add(importableColumn.getHeaderName()); + } + String validationMessage = _("csv.import.error.unrecognizedHeaders", + StringUtil.join(csvHeaders, ", ", true), + StringUtil.join(validHeaderNames, ", ", true)); + throw new ImportRuntimeException(validationMessage); + } + } + + protected void checkUniqueModelColumnNames() { + Set<String> headerNames = new HashSet<String>(); + Set<String> doubleHeaderNames = new HashSet<String>(); + for (ImportableColumn<E, ?> importableColumn : + model.getColumnsForImport()) { + String headerName = importableColumn.getHeaderName(); + boolean alreadyUsed = !headerNames.add(headerName); + if (alreadyUsed) { + doubleHeaderNames.add(headerName); + } + } + if (!doubleHeaderNames.isEmpty()) { + String message = _("csv.import.error.duplicatedHeaders", + StringUtil.join(doubleHeaderNames, ", ", true)); + + throw new ImportRuntimeException( + message); + } + } + + protected void checkAllManadatoryHeadersArePresent(String[] headers) { + + List<String> csvHeaders = new ArrayList<String>(); + Collections.addAll(csvHeaders, headers); + + List<String> mandatoryHeadersNames = new ArrayList<String>(); + for (ImportableColumn<E, ?> field : getAllMandatoryHeaders()) { + mandatoryHeadersNames.add(field.getHeaderName()); + } + mandatoryHeadersNames.removeAll(csvHeaders); + + if (!mandatoryHeadersNames.isEmpty()) { + String validationMessage = _("csv.import.error.missingMandatoryHeaders", + StringUtil.join(mandatoryHeadersNames, ", ", true)); + throw new ImportRuntimeException(validationMessage); + } + + Set<String> headerNames = new HashSet<String>(); + for (ImportableColumn<E, ?> importableColumn : + model.getColumnsForImport()) { + String headerName = importableColumn.getHeaderName(); + boolean alreadyUsed = !headerNames.add(headerName); + if (alreadyUsed) { + throw new ImportRuntimeException( + "model contains multiple columnsForImport named '" + + headerName + "'"); + } + } + } + + protected String[] getHeaders() throws ImportRuntimeException { + try { + boolean canReadHeaders = reader.readHeaders(); + if (!canReadHeaders) { + throw new ImportRuntimeException("can't read headers"); + } + } catch (IOException e) { + throw new ImportRuntimeException("can't read headers"); + } + + try { + String[] result = reader.getHeaders(); + return result; + } catch (IOException eee) { + throw new ImportRuntimeException("can't get headers", eee); + } + } + protected List<ImportableColumn<E, Object>> getNonIgnoredHeaders() { List<ImportableColumn<E, Object>> nonIgnoredHeaders = new ArrayList<ImportableColumn<E, Object>>(); for (ImportableColumn<E, Object> field : model.getColumnsForImport()) { @@ -279,18 +345,6 @@ this.reader.setTrimWhitespace(true); } - protected boolean validateModel() { - Set<String> headerNames = new HashSet<String>(); - for (ImportableColumn<E, ?> importableColumn : model.getColumnsForImport()) { - String headerName = importableColumn.getHeaderName(); - boolean alreadyUsed = !headerNames.add(headerName); - if (alreadyUsed) { - throw new IllegalArgumentException("model contains multiple columnsForImport named '" + headerName + "'"); - } - } - return true; - } - protected void readFirstLine() throws ImportRuntimeException { try { boolean emptyFile = !reader.readRecord(); @@ -304,5 +358,4 @@ } } - } Added: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/ImportToMap.java =================================================================== --- trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/ImportToMap.java (rev 0) +++ trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/ImportToMap.java 2011-11-30 17:12:49 UTC (rev 2244) @@ -0,0 +1,165 @@ +/* + * #%L + * Nuiton Utils :: Nuiton Csv + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2011 CodeLutin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/lgpl-3.0.html>. + * #L% + */ +package org.nuiton.util.csv; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; + +import static org.nuiton.i18n.I18n._; + +/** + * A extended {@link Import} to read csv lines into a single map. + * <p/> + * <strong>Warning:</strong> The map used to push values for a csv line is the + * same for all lines, it means you have to copy to your own object. + * + * @author tchemit <chemit@codelutin.com> + * @since 2.4 + */ +public class ImportToMap extends Import<Map<String, Object>> { + + /** Logger. */ + private static final Log log = LogFactory.getLog(ImportToMap.class); + + public static ImportToMap newImport(ImportModel<Map<String, Object>> model, + InputStream inputStream) { + return new ImportToMap(model, inputStream); + } + + public static ImportToMap newImport(ImportModel<Map<String, Object>> model, + Reader reader) { + return new ImportToMap(model, reader); + } + + @Override + public Iterator<Map<String, Object>> iterator() { + + // obtain headers from csv input and validate the model + prepareAndValidate(); + + // read first line since first line is header + readFirstLine(); + + return new Iterator<Map<String, Object>>() { + + boolean hasNext = true; + + int lineNumber; + + Map<String, Object> element = new HashMap<String, Object>(); + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public Map<String, Object> next() + throws NoSuchElementException, ImportRuntimeException { + + if (!hasNext) { + throw new NoSuchElementException(); + } + + lineNumber += 1; + + // clean all values from the element + element.clear(); + + for (ImportableColumn<Map<String, Object>, Object> field : + getNonIgnoredHeaders()) { + + // read value from csv cell + String value; + try { + value = reader.get(field.getHeaderName()); + } catch (Exception e) { + reader.close(); + throw new ImportRuntimeException(_("csv.import.error.unableToReadField", + field.getHeaderName(), lineNumber), e); + } + + // contravariance ftw + Object parsedValue; + try { + parsedValue = field.parseValue(value); + } catch (Exception e) { + String message = _("csv.import.error.unableToParseValue", + value, field.getHeaderName(), lineNumber) + + "\n" + e.getMessage(); + throw new ImportRuntimeException(message, e); + } + + // set value to element + try { + field.setValue(element, parsedValue); + } catch (Exception e) { + String message = _("csv.import.error.unableToSetValue", + parsedValue, + element.toString(), + lineNumber, field.getHeaderName()); + if (log.isErrorEnabled()) { + log.error(message); + } + throw new ImportRuntimeException(message, e); + } + } + + try { + hasNext = reader.readRecord(); + } catch (IOException e) { + reader.close(); + throw new ImportRuntimeException( + _("csv.import.error.unableToReadLine", lineNumber + 1), e); + } + + return element; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + protected ImportToMap(ImportModel<Map<String, Object>> mapImportModel, + InputStream inputStream) { + super(mapImportModel, inputStream); + } + + protected ImportToMap(ImportModel<Map<String, Object>> mapImportModel, + Reader reader) { + super(mapImportModel, reader); + } +} Property changes on: trunk/nuiton-csv/src/main/java/org/nuiton/util/csv/ImportToMap.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Modified: trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_en_GB.properties =================================================================== --- trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_en_GB.properties 2011-11-30 09:00:26 UTC (rev 2243) +++ trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_en_GB.properties 2011-11-30 17:12:49 UTC (rev 2244) @@ -1,4 +1,7 @@ +csv.import.error.duplicatedHeaders=Fields %s are duplicated. +csv.import.error.missingMandatoryHeaders=The mandatory fields %s are missing csv.import.error.unableToParseValue=Unable to parse value '%s' (column '%s', line %s) csv.import.error.unableToReadField=Unable to read value of column '%s' at line %s csv.import.error.unableToReadLine=Unable to read line %s -csv.import.error.unableToSetValue=Unable to set value '%s' (entity '%s', line %s, column '%s') +csv.import.error.unableToSetValue=Unable to set value '%s' (object '%s', line %s, column '%s') +csv.import.error.unrecognizedHeaders=Fields %s are not recognized. Accepted fields are %s. Modified: trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_es_ES.properties =================================================================== --- trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_es_ES.properties 2011-11-30 09:00:26 UTC (rev 2243) +++ trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_es_ES.properties 2011-11-30 17:12:49 UTC (rev 2244) @@ -1,4 +1,7 @@ +csv.import.error.duplicatedHeaders=Fields %s are duplicated. +csv.import.error.missingMandatoryHeaders=The mandatory fields %s are missing csv.import.error.unableToParseValue=Unable to parse value '%s' (column '%s', line %s) csv.import.error.unableToReadField=Unable to read value of column '%s' at line %s csv.import.error.unableToReadLine=Unable to read line %s -csv.import.error.unableToSetValue=Unable to set value '%s' (entity '%s', line %s, column '%s') +csv.import.error.unableToSetValue=Unable to set value '%s' (object'%s', line %s, column '%s') +csv.import.error.unrecognizedHeaders=Fields %s are not recognized. Accepted fields are %s. Modified: trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_fr_FR.properties =================================================================== --- trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_fr_FR.properties 2011-11-30 09:00:26 UTC (rev 2243) +++ trunk/nuiton-csv/src/main/resources/i18n/nuiton-csv_fr_FR.properties 2011-11-30 17:12:49 UTC (rev 2244) @@ -1,4 +1,7 @@ +csv.import.error.duplicatedHeaders=Les champs %s sont dupliqués. +csv.import.error.missingMandatoryHeaders=Les champs obligatoires %s sont manquants csv.import.error.unableToParseValue=Erreur lors de l'interprétation de la valeur '%s' (colonne '%s', ligne %s) csv.import.error.unableToReadField=Impossible de lire la colonne '%s' à la ligne %s csv.import.error.unableToReadLine=Impossible de lire la ligne %s -csv.import.error.unableToSetValue=Impossible d'enregistrer la valeur '%s' (entité '%s', ligne %s, column '%s') +csv.import.error.unableToSetValue=Impossible d'enregistrer la valeur '%s' (objet '%s', ligne %s, column '%s') +csv.import.error.unrecognizedHeaders=Les champs %s ne sont pas reconnus. Les champs possibles sont %s. Modified: trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java =================================================================== --- trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java 2011-11-30 09:00:26 UTC (rev 2243) +++ trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java 2011-11-30 17:12:49 UTC (rev 2244) @@ -21,7 +21,14 @@ */ package org.nuiton.util.csv; -import java.io.IOException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.nuiton.util.DateUtil; +import org.nuiton.util.csv.Common.BeanProperty; + import java.io.InputStream; import java.text.DateFormat; import java.text.ParseException; @@ -32,14 +39,6 @@ import java.util.Iterator; import java.util.List; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.nuiton.util.DateUtil; -import org.nuiton.util.csv.Common.BeanProperty; - /** * Created on 28/11/11 * @@ -60,8 +59,7 @@ * @throws Exception for errors */ @Test - public void testSimpleImport() - throws Exception { + public void testSimpleImport() throws Exception { execute(new SimpleImportModel(dateFormat)); } @@ -71,18 +69,16 @@ * @throws Exception for errors */ @Test - public void testColumnImport() - throws Exception { + public void testColumnImport() throws Exception { execute(new ColumnImportModel(dateFormat)); } - private void execute(ImportModel<Row> model) - throws IOException { + private void execute(ImportModel<Row> model) { InputStream csvStream = getClass().getResourceAsStream("importTest.csv"); Import<Row> rowImport = Import.newImport(model, csvStream); try { - Iterator<Row> it = rowImport.startImport(); + Iterator<Row> it = rowImport.iterator(); List<Row> rows = newList(it); Assert.assertEquals(3, rows.size()); Row row1 = rows.get(0); @@ -98,13 +94,13 @@ Assert.assertEquals(new Integer(21), row3.getNumber()); Assert.assertEquals("3ème ligne", row3.getTitle()); } finally { - rowImport.stopImport(); + rowImport.close(); } } private static <T> List<T> newList(Iterator<T> iterator) { List<T> result = new ArrayList<T>(); - while(iterator.hasNext()) { + while (iterator.hasNext()) { result.add(iterator.next()); } return result; @@ -274,14 +270,13 @@ } @Override - public String parseValue(String value) - throws ParseException { + public String parseValue(String value) { return value; } @Override public void update(Row object, - String value) + String value) throws Exception { object.setTitle(value); } @@ -340,8 +335,7 @@ } @Override - public Integer parseValue(String value) - throws ParseException { + public Integer parseValue(String value) { return Integer.parseInt(value); } @@ -365,7 +359,7 @@ } protected abstract void update(E object, F value) - throws Exception; + throws Exception; } } // $Id$ Property changes on: trunk/nuiton-csv/src/test/java/org/nuiton/util/csv/ImportTest.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native Property changes on: trunk/nuiton-csv/src/test/resources/org/nuiton/util/csv/importTest.csv ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: svn:eol-style + native