diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/AbstractExcelItemReader.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/AbstractExcelItemReader.java index 9b9c45f..5e8600f 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/AbstractExcelItemReader.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/AbstractExcelItemReader.java @@ -17,13 +17,13 @@ package org.springframework.batch.item.excel; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.batch.item.excel.support.rowset.*; import org.springframework.batch.item.file.ResourceAwareItemReaderItemStream; import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; -import org.springframework.util.ObjectUtils; import java.io.IOException; import java.io.InputStream; @@ -49,7 +49,8 @@ public abstract class AbstractExcelItemReader extends AbstractItemCountingIte private RowCallbackHandler skippedRowsCallback; private boolean noInput = false; private boolean strict = true; - private RowSet rs; + private RowSetFactory rowSetFactory = new DefaultRowSetFactory(); + private RowSet rs; public AbstractExcelItemReader() { super(); @@ -62,25 +63,25 @@ public abstract class AbstractExcelItemReader extends AbstractItemCountingIte return null; } - if (rs.next()) { - try { - return this.rowMapper.mapRow(rs); - } catch (final Exception e) { - throw new ExcelFileParseException("Exception parsing Excel file.", e, this.resource.getDescription(), - rs.getMetaData().getSheetName(), rs.getCurrentRowIndex(), rs.getCurrentRow()); - } - } else { - this.currentSheet++; - if (this.currentSheet >= this.getNumberOfSheets()) { - if (logger.isDebugEnabled() ) { - logger.debug("No more sheets in '" + this.resource.getDescription() + "'."); - } - return null; - } else { - this.openSheet(); - return this.doRead(); - } - } + if (rs.next()) { + try { + return this.rowMapper.mapRow(rs); + } catch (final Exception e) { + throw new ExcelFileParseException("Exception parsing Excel file.", e, this.resource.getDescription(), + rs.getMetaData().getSheetName(), rs.getCurrentRowIndex(), rs.getCurrentRow()); + } + } else { + this.currentSheet++; + if (this.currentSheet >= this.getNumberOfSheets()) { + if (logger.isDebugEnabled()) { + logger.debug("No more sheets in '" + this.resource.getDescription() + "'."); + } + return null; + } else { + this.openSheet(); + return this.doRead(); + } + } } @Override @@ -92,7 +93,7 @@ public abstract class AbstractExcelItemReader extends AbstractItemCountingIte throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode): " + this.resource); } - logger.warn("Input resource does not exist '"+this.resource.getDescription()+"'."); + logger.warn("Input resource does not exist '" + this.resource.getDescription() + "'."); return; } @@ -101,7 +102,7 @@ public abstract class AbstractExcelItemReader extends AbstractItemCountingIte throw new IllegalStateException("Input resource must be readable (reader is in 'strict' mode): " + this.resource); } - logger.warn("Input resource is not readable '"+this.resource.getDescription()+"'."); + logger.warn("Input resource is not readable '" + this.resource.getDescription() + "'."); return; } @@ -109,7 +110,7 @@ public abstract class AbstractExcelItemReader extends AbstractItemCountingIte this.openSheet(); this.noInput = false; if (logger.isDebugEnabled()) { - logger.debug("Opened workbook ["+this.resource.getFilename()+"] with "+this.getNumberOfSheets()+" sheets."); + logger.debug("Opened workbook [" + this.resource.getFilename() + "] with " + this.getNumberOfSheets() + " sheets."); } } @@ -123,19 +124,20 @@ public abstract class AbstractExcelItemReader extends AbstractItemCountingIte private void openSheet() { final Sheet sheet = this.getSheet(this.currentSheet); - this.rs = new RowSet(sheet); + this.rs =rowSetFactory.create(sheet); - if (logger.isDebugEnabled()) { - logger.debug("Opening sheet "+sheet.getName()+"."); + + if (logger.isDebugEnabled()) { + logger.debug("Opening sheet " + sheet.getName() + "."); } - for (int i = 0; i < this.linesToSkip; i++) { + for (int i = 0; i < this.linesToSkip; i++) { if (rs.next() && this.skippedRowsCallback != null) { this.skippedRowsCallback.handleRow(rs); } } if (logger.isDebugEnabled()) { - logger.debug("Openend sheet "+sheet.getName()+", with "+sheet.getNumberOfRows()+" rows."); + logger.debug("Openend sheet " + sheet.getName() + ", with " + sheet.getNumberOfRows() + " rows."); } } @@ -199,6 +201,10 @@ public abstract class AbstractExcelItemReader extends AbstractItemCountingIte this.rowMapper = rowMapper; } + public void setRowSetFactory(RowSetFactory rowSetFactory) { + this.rowSetFactory = rowSetFactory; + } + public void setSkippedRowsCallback(final RowCallbackHandler skippedRowsCallback) { this.skippedRowsCallback = skippedRowsCallback; } diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/ExcelFileParseException.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/ExcelFileParseException.java index 72e312d..b9a8928 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/ExcelFileParseException.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/ExcelFileParseException.java @@ -19,9 +19,9 @@ import org.springframework.batch.item.ParseException; /** * Exception thrown when parsing excel files. The name of the sheet, the row number on that sheet and the - * name of the excel file can be passed in so that in exception handling we can reuse it. This class only has + * name of the excel file can be passed in so that in exception handling we can reuse it. This class only has * simply dependencies to make it is generic as possible. - * + * * @author Marten Deinum * @since 0.5.0 */ @@ -34,16 +34,16 @@ public class ExcelFileParseException extends ParseException { /** * Construct an {@link ExcelFileParseException}. - * - * @param message the message - * @param cause the root cause - * @param filename the name of the excel file - * @param sheet the name of the sheet + * + * @param message the message + * @param cause the root cause + * @param filename the name of the excel file + * @param sheet the name of the sheet * @param rowNumber the row number in the current sheet - * @param row the row data as text + * @param row the row data as text */ public ExcelFileParseException(final String message, final Throwable cause, final String filename, - final String sheet, final int rowNumber, final String[] row) { + final String sheet, final int rowNumber, final String[] row) { super(message, cause); this.filename = filename; this.sheet = sheet; diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowCallbackHandler.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowCallbackHandler.java index c1dc7ff..8b5e4cb 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowCallbackHandler.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowCallbackHandler.java @@ -16,9 +16,11 @@ package org.springframework.batch.item.excel; +import org.springframework.batch.item.excel.support.rowset.RowSet; + /** * Callback to handle skipped lines. Useful for header/footer processing. - * + * * @author Marten Deinum * @since 0.5.0 */ diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowMapper.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowMapper.java index 5e43430..6bda223 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowMapper.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowMapper.java @@ -15,21 +15,22 @@ */ package org.springframework.batch.item.excel; +import org.springframework.batch.item.excel.support.rowset.RowSet; + /** * Map rows from an excel sheet to an object. - * - * @author Marten Deinum - * @since 0.5.0 * * @param + * @author Marten Deinum + * @since 0.5.0 */ public interface RowMapper { /** - * Implementations must implement this method to map the provided row to + * Implementations must implement this method to map the provided row to * the parameter type T. The row number represents the number of rows * into a {@link Sheet} the current line resides. - * + * * @param rs the RowSet used for mapping. * @return mapped object of type T * @throws Exception if error occured while parsing. diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowSet.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowSet.java deleted file mode 100644 index 89a2301..0000000 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowSet.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.springframework.batch.item.excel; - -import java.util.Properties; - -/** - * @author Marten Deinum - */ -public class RowSet { - - private final Sheet sheet; - private final RowSetMetaData metaData; - - private int currentRowIndex = -1; - private String[] currentRow; - - public RowSet(Sheet sheet) { - this.sheet=sheet; - this.metaData = new RowSetMetaData(sheet); - } - - public RowSetMetaData getMetaData() { - return metaData; - } - - public boolean next() { - currentRow = null; - currentRowIndex++; - if (currentRowIndex <= sheet.getNumberOfRows()) { - currentRow = sheet.getRow(currentRowIndex); - return true; - } - return false; - } - - /** - * The current row index represents the number of rows - * into a {@link Sheet} the current line resides - */ - public int getCurrentRowIndex() { - return this.currentRowIndex; - } - - /** - * Get the data of the current row. - * - * @return a String[] for the current data - */ - public String[] getCurrentRow() { - return this.currentRow; - } - - /** - * Get the value of the given column - * - * @param idx index of the column to get, 0 based - * @return the value - * @throws java.lang.ArrayIndexOutOfBoundsException - */ - public String getColumnValue(int idx) { - return currentRow[idx]; - } - - /** - * Construct name-value pairs from the column names and string values. Null - * values are omitted. - * - * @return some properties representing the row set. - * - * @throws IllegalStateException if the column name meta data is not - * available. - */ - public Properties getProperties() { - final String[] names = metaData.getColumnNames(); - if (names == null) { - throw new IllegalStateException("Cannot create properties without meta data"); - } - - Properties props = new Properties(); - for (int i = 0; i < currentRow.length; i++) { - String value = currentRow[i]; - if (value != null) { - props.setProperty(names[i], value); - } - } - return props; - } -} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowSetMetaData.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowSetMetaData.java deleted file mode 100644 index e270b16..0000000 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowSetMetaData.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.springframework.batch.item.excel; - -/** - * Created by in329dei on 3-9-2014. - */ -public class RowSetMetaData { - - private final Sheet sheet; - - RowSetMetaData(Sheet sheet) { - this.sheet = sheet; - } - - public String[] getColumnNames() { - return sheet.getHeader(); - } - - public String getColumnName(int idx) { - String[] names = getColumnNames(); - return names[idx]; - } - - public int getColumnCount() { - return sheet.getNumberOfColumns(); - } - - public String getSheetName() { - return sheet.getName(); - } - -} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/Sheet.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/Sheet.java index c583ac6..a3d0ce7 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/Sheet.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/Sheet.java @@ -17,46 +17,38 @@ package org.springframework.batch.item.excel; /** - * Interface to wrap different Excel implementations like JExcel, JXL or Apache POI. - * + * Interface to wrap different Excel implementations like JExcel, JXL or Apache POI. + * * @author Marten Deinum * @since 0.5.0 - * */ public interface Sheet { /** * Get the number of rows in this sheet. - * + * * @return the number of rows. */ int getNumberOfRows(); /** * Get the name of the sheet. - * + * * @return the name of the sheet. */ String getName(); /** * Get the row as a String[]. Returns null if the row doesn't exist. - * + * * @param rowNumber the row number to read. * @return a String[] or null */ String[] getRow(int rowNumber); - /** - * Gets the first row of the sheet and use it as header. - * - * @return String[] of row 0 - */ - String[] getHeader(); - /** * The number of columns in this sheet. - * + * * @return number of columns */ int getNumberOfColumns(); diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlItemReader.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlItemReader.java index fc13409..816cbbd 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlItemReader.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlItemReader.java @@ -28,11 +28,10 @@ import org.springframework.util.ClassUtils; * {@link org.springframework.batch.item.ItemReader} implementation which uses the JExcelApi to read an Excel * file. It will read the file sheet for sheet and row for row. It is based on * the {@link org.springframework.batch.item.file.FlatFileItemReader} - * - * @author Marten Deinum - * @since 0.5.0 * * @param the type + * @author Marten Deinum + * @since 0.5.0 */ public class JxlItemReader extends AbstractExcelItemReader { diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlSheet.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlSheet.java index cb5542a..9ab039a 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlSheet.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlSheet.java @@ -22,7 +22,7 @@ import org.springframework.batch.item.excel.Sheet; /** * {@link org.springframework.batch.item.excel.Sheet} implementation for JXL. - * + * * @author Marten Deinum * @since 0.5.0 */ @@ -32,7 +32,7 @@ public class JxlSheet implements Sheet { /** * Constructor which takes the delegate sheet. - * + * * @param delegate the JXL sheet */ JxlSheet(final jxl.Sheet delegate) { @@ -48,25 +48,17 @@ public class JxlSheet implements Sheet { return this.delegate.getRows(); } - /** - * {@inheritDoc} - */ - @Override - public String[] getHeader() { - return this.getRow(0); - } - /** * {@inheritDoc} */ @Override public String[] getRow(final int rowNumber) { - if (rowNumber < getNumberOfRows()) { - final Cell[] row = this.delegate.getRow(rowNumber); - return JxlUtils.extractContents(row); - } else { - return null; - } + if (rowNumber < getNumberOfRows()) { + final Cell[] row = this.delegate.getRow(rowNumber); + return JxlUtils.extractContents(row); + } else { + return null; + } } /** diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlUtils.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlUtils.java index 3009f5e..f579198 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlUtils.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlUtils.java @@ -32,13 +32,15 @@ import java.util.List; */ public final class JxlUtils { - /** Private constructor to prevent easy instantiation. */ + /** + * Private constructor to prevent easy instantiation. + */ private JxlUtils() { } /** * Checks if the given cell is emtpy. The cell is empty if it contains no characters, it will trim spaces. - + * * @param cell to check * @return true/false * @see org.springframework.util.StringUtils#hasText(String) @@ -68,7 +70,7 @@ public final class JxlUtils { /** * Check if the given workbook has any sheets. - * + * * @param workbook to check * @return true/false */ @@ -77,8 +79,8 @@ public final class JxlUtils { } /** - * Extract the content from the given row. - * + * Extract the content from the given row. + * * @param row the row * @return the content as String[] */ diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/BeanPropertyRowMapper.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/BeanPropertyRowMapper.java new file mode 100644 index 0000000..2634b21 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/BeanPropertyRowMapper.java @@ -0,0 +1,323 @@ +/* + * Copyright 2006-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.excel.mapping; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.batch.item.excel.RowMapper; +import org.springframework.batch.item.excel.support.rowset.RowSet; +import org.springframework.batch.item.excel.support.rowset.RowSetMetaData; +import org.springframework.beans.*; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import java.beans.PropertyDescriptor; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * {@link RowMapper} implementation that converts a row into a new instance + * of the specified mapped target class. The mapped target class must be a + * top-level class and it must have a default or no-arg constructor. + * + *

Column values are mapped based on matching the column name as obtained from row set + * metadata to public setters for the corresponding properties. The names are matched either + * directly or by transforming a name separating the parts with underscores to the same name + * using "camel" case. + * + *

Mapping is provided for fields in the target class for many common types, e.g.: + * String, boolean, Boolean, byte, Byte, short, Short, int, Integer, long, Long, + * float, Float, double, Double, BigDecimal, {@code java.util.Date}, etc. + * + *

For 'null' values read from the Excel document, we will attempt to call the setter, but in the case of + * Java primitives, this causes a TypeMismatchException. This class can be configured (using the + * primitivesDefaultedForNullValue property) to trap this exception and use the primitives default value. + * Be aware that if you use the values from the generated bean to update the database the primitive value + * will have been set to the primitive's default value instead of null. + * + *

Please note that this class is designed to provide convenience rather than high performance. + * For best performance, consider using a custom {@link RowMapper} implementation. + * + * @author Marten Deinum + * @since 0.5.0 + */ +public class BeanPropertyRowMapper implements RowMapper, BeanFactoryAware, InitializingBean { + + /** + * Logger available to subclasses + */ + protected final Log logger = LogFactory.getLog(getClass()); + + /** + * The class we are mapping to + */ + private Class type; + + /** + * The name of the bean we are mapping to + */ + private String name; + + /** + * Whether we're strictly validating + */ + private boolean checkFullyPopulated = false; + + /** + * Whether we're defaulting primitives when mapping a null value + */ + private boolean primitivesDefaultedForNullValue = false; + + /** + * Map of the fields we provide mapping for + */ + private Map mappedFields; + + /** + * Set of bean properties we provide mapping for + */ + private Set mappedProperties; + + private BeanFactory beanFactory; + + /** + * Create a new BeanPropertyRowMapper for bean-style configuration. + * + * @see #setTargetType + * @see #setPrototypeBeanName + * @see #setCheckFullyPopulated + */ + public BeanPropertyRowMapper() { + } + + + /** + * The bean name (id) for an object that can be populated from the field set + * that will be passed into {@link #mapRow(RowSet)}. Typically a + * prototype scoped bean so that a new instance is returned for each field + * set mapped. + *

+ * Either this property or the type property must be specified, but not + * both. + * + * @param name the name of a prototype bean in the enclosing BeanFactory + */ + public void setPrototypeBeanName(String name) { + this.name = name; + } + + /** + * Public setter for the type of bean to create instead of using a prototype + * bean. An object of this type will be created from its default constructor + * for every call to {@link #mapRow(RowSet)}.
+ *

+ * Either this property or the prototype bean name must be specified, but + * not both. + * + * @param type the type to set + */ + public void setTargetType(Class type) { + this.type = type; + } + + /** + * Initialize the mapping metadata for the given class. + * + * @param mappedClass the mapped class. + */ + protected void initialize(Class mappedClass) { + this.mappedFields = new HashMap(); + this.mappedProperties = new HashSet(); + PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass); + for (PropertyDescriptor pd : pds) { + if (pd.getWriteMethod() != null) { + this.mappedFields.put(pd.getName().toLowerCase(), pd); + String underscoredName = underscoreName(pd.getName()); + if (!pd.getName().toLowerCase().equals(underscoredName)) { + this.mappedFields.put(underscoredName, pd); + } + this.mappedProperties.add(pd.getName()); + } + } + } + + /** + * Convert a name in camelCase to an underscored name in lower case. + * Any upper case letters are converted to lower case with a preceding underscore. + * + * @param name the string containing original name + * @return the converted name + */ + private String underscoreName(String name) { + if (!StringUtils.hasLength(name)) { + return ""; + } + StringBuilder result = new StringBuilder(); + result.append(name.substring(0, 1).toLowerCase()); + for (int i = 1; i < name.length(); i++) { + String s = name.substring(i, i + 1); + String slc = s.toLowerCase(); + if (!s.equals(slc)) { + result.append("_").append(slc); + } else { + result.append(s); + } + } + return result.toString(); + } + + /** + * Set whether we're strictly validating that all bean properties have been + * mapped from corresponding database fields. + *

Default is {@code false}, accepting unpopulated properties in the + * target bean. + */ + public void setCheckFullyPopulated(boolean checkFullyPopulated) { + this.checkFullyPopulated = checkFullyPopulated; + } + + /** + * Return whether we're strictly validating that all bean properties have been + * mapped from corresponding database fields. + */ + public boolean isCheckFullyPopulated() { + return this.checkFullyPopulated; + } + + /** + * Set whether we're defaulting Java primitives in the case of mapping a null value + * from corresponding database fields. + *

Default is {@code false}, throwing an exception when nulls are mapped to Java primitives. + */ + public void setPrimitivesDefaultedForNullValue(boolean primitivesDefaultedForNullValue) { + this.primitivesDefaultedForNullValue = primitivesDefaultedForNullValue; + } + + /** + * Return whether we're defaulting Java primitives in the case of mapping a null value + * from corresponding database fields. + */ + public boolean isPrimitivesDefaultedForNullValue() { + return primitivesDefaultedForNullValue; + } + + /** + * Extract the values for all columns in the current row. + *

Utilizes public setters and result set metadata. + * + * @see java.sql.ResultSetMetaData + */ + @Override + public T mapRow(RowSet rs) throws Exception { + T mappedObject = getBean(); + BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject); + initBeanWrapper(bw); + + RowSetMetaData rsmd = rs.getMetaData(); + int columnCount = rsmd.getColumnCount(); + Set populatedProperties = (isCheckFullyPopulated() ? new HashSet() : null); + + for (int index = 0; index < columnCount; index++) { + String column = rsmd.getColumnName(index); + PropertyDescriptor pd = this.mappedFields.get(column.replaceAll(" ", "").toLowerCase()); + if (pd != null) { + String value = rs.getColumnValue(index); + if (logger.isDebugEnabled()) { + logger.debug("Mapping column '" + column + "' to property '" + + pd.getName() + "' of type " + pd.getPropertyType()); + } + try { + + bw.setPropertyValue(pd.getName(), value); + } catch (TypeMismatchException e) { + if (value == null && primitivesDefaultedForNullValue) { + logger.debug("Intercepted TypeMismatchException for row " + rs.getCurrentRowIndex() + + " on sheet " + rsmd.getSheetName() + " and column '" + column + "' with value " + value + + " when setting property '" + pd.getName() + "' of type " + pd.getPropertyType() + + " on object: " + mappedObject); + } else { + throw e; + } + } + if (populatedProperties != null) { + populatedProperties.add(pd.getName()); + } + } + } + + if (populatedProperties != null && !populatedProperties.equals(this.mappedProperties)) { + throw new IllegalStateException("Given RowSet does not contain all fields " + + "necessary to populate object of class [" + mappedObject.getClass() + "]: " + this.mappedProperties); + } + + return mappedObject; + } + + /** + * Initialize the given BeanWrapper to be used for row mapping. + * To be called for each row. + *

The default implementation is empty. Can be overridden in subclasses. + * + * @param bw the BeanWrapper to initialize + */ + protected void initBeanWrapper(BeanWrapper bw) { + } + + private T getBean() { + if (name != null) { + return (T) beanFactory.getBean(name); + } + try { + return type.newInstance(); + } catch (InstantiationException e) { + ReflectionUtils.handleReflectionException(e); + } catch (IllegalAccessException e) { + ReflectionUtils.handleReflectionException(e); + } + // should not happen + throw new IllegalStateException("Internal error: could not create bean instance for mapping."); + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.state(name != null || type != null, "Either name or type must be provided."); + Assert.state(name == null || type == null, "Both name and type cannot be specified together."); + initialize((Class) getBean().getClass()); + } + + /** + * Static factory method to create a new BeanPropertyRowMapper + * (with the mapped class specified only once). + * + * @param targetType the class that each row should be mapped to + */ + public static BeanPropertyRowMapper newInstance(Class targetType) { + BeanPropertyRowMapper newInstance = new BeanPropertyRowMapper(); + newInstance.setTargetType(targetType); + return newInstance; + } +} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/DefaultRowMapper.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/DefaultRowMapper.java deleted file mode 100644 index 52f13f3..0000000 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/DefaultRowMapper.java +++ /dev/null @@ -1,66 +0,0 @@ - -/* - * Copyright 2006-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.batch.item.excel.mapping; - -import org.springframework.batch.item.excel.RowMapper; -import org.springframework.batch.item.excel.RowSet; -import org.springframework.batch.item.excel.Sheet; -import org.springframework.batch.item.excel.transform.DefaultRowTokenizer; -import org.springframework.batch.item.excel.transform.RowTokenizer; -import org.springframework.batch.item.file.mapping.FieldSetMapper; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - -/** - * {@link RowMapper} implementation which delegates to a {@link RowTokenizer} and a {@link org.springframework.batch.item.file.mapping.FieldSetMapper} the mapping - * of fields and construction of objects. - * - * @author Marten Deinum - * @since 0.5.0 - * - * @param - */ -public class DefaultRowMapper implements RowMapper, InitializingBean { - - private RowTokenizer rowTokenizer = new DefaultRowTokenizer(); - private FieldSetMapper fieldSetMapper; - - @Override - public T mapRow(RowSet rs) throws Exception { - return this.fieldSetMapper.mapFieldSet(this.rowTokenizer.tokenize(rs)); - } - - public void setFieldSetMapper(final FieldSetMapper fieldSetMapper) { - this.fieldSetMapper = fieldSetMapper; - } - - /** - * Set the {@link RowTokenizer} to use to create a {@link org.springframework.batch.item.file.transform.FieldSet}. Default uses the {@link DefaultRowTokenizer}. - * - * @param rowTokenizer to use - */ - public void setRowTokenizer(final RowTokenizer rowTokenizer) { - this.rowTokenizer = rowTokenizer; - } - - @Override - public void afterPropertiesSet() throws Exception { - Assert.notNull(this.rowTokenizer, "The RowTokenizer must be set"); - Assert.notNull(this.fieldSetMapper, "The FieldSetMapper must be set"); - } -} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapper.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapper.java index 22f4174..3987dfc 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapper.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapper.java @@ -16,16 +16,14 @@ package org.springframework.batch.item.excel.mapping; import org.springframework.batch.item.excel.RowMapper; -import org.springframework.batch.item.excel.RowSet; -import org.springframework.batch.item.excel.Sheet; +import org.springframework.batch.item.excel.support.rowset.RowSet; /** * Pass through {@link RowMapper} useful for passing the orginal String[] * back directly rather than a mapped object. - * + * * @author Marten Deinum * @since 0.5.0 - * */ public class PassThroughRowMapper implements RowMapper { diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiItemReader.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiItemReader.java index d51aac7..f94f749 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiItemReader.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiItemReader.java @@ -28,10 +28,9 @@ import org.springframework.core.io.Resource; * file. It will read the file sheet for sheet and row for row. It is based on * the {@link org.springframework.batch.item.file.FlatFileItemReader} * + * @param the type * @author Marten Deinum * @since 0.5.0 - * - * @param the type */ public class PoiItemReader extends AbstractExcelItemReader { diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiSheet.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiSheet.java index 423f3e0..978776f 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiSheet.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiSheet.java @@ -26,7 +26,7 @@ import java.util.List; /** * Sheet implementation for Apache POI. - * + * * @author Marten Deinum * @since 0.5.0 */ @@ -38,7 +38,7 @@ public class PoiSheet implements Sheet { /** * Constructor which takes the delegate sheet. - * + * * @param delegate the apache POI sheet */ PoiSheet(final org.apache.poi.ss.usermodel.Sheet delegate) { @@ -67,44 +67,36 @@ public class PoiSheet implements Sheet { */ @Override public String[] getRow(final int rowNumber) { - if (rowNumber > this.delegate.getLastRowNum()) { + final Row row = this.delegate.getRow(rowNumber); + if (row == null) { return null; } - final Row row = this.delegate.getRow(rowNumber); final List cells = new LinkedList(); - for (int i =0; i< getNumberOfColumns(); i++) { + for (int i = 0; i < getNumberOfColumns(); i++) { Cell cell = row.getCell(i); switch (cell.getCellType()) { - case Cell.CELL_TYPE_NUMERIC: - cells.add(String.valueOf(cell.getNumericCellValue())); - break; - case Cell.CELL_TYPE_BOOLEAN: - cells.add(String.valueOf(cell.getBooleanCellValue())); - break; - case Cell.CELL_TYPE_STRING: - case Cell.CELL_TYPE_BLANK: - cells.add(cell.getStringCellValue()); - break; - case Cell.CELL_TYPE_FORMULA: - FormulaEvaluator evaluator = delegate.getWorkbook().getCreationHelper().createFormulaEvaluator(); - cells.add(evaluator.evaluate(cell).formatAsString()); - break; - default: - throw new IllegalArgumentException("Cannot handle cells of type " + cell.getCellType()); + case Cell.CELL_TYPE_NUMERIC: + cells.add(String.valueOf(cell.getNumericCellValue())); + break; + case Cell.CELL_TYPE_BOOLEAN: + cells.add(String.valueOf(cell.getBooleanCellValue())); + break; + case Cell.CELL_TYPE_STRING: + case Cell.CELL_TYPE_BLANK: + cells.add(cell.getStringCellValue()); + break; + case Cell.CELL_TYPE_FORMULA: + FormulaEvaluator evaluator = delegate.getWorkbook().getCreationHelper().createFormulaEvaluator(); + cells.add(evaluator.evaluate(cell).formatAsString()); + break; + default: + throw new IllegalArgumentException("Cannot handle cells of type " + cell.getCellType()); } } return cells.toArray(new String[cells.size()]); } - /** - * {@inheritDoc} - */ - @Override - public String[] getHeader() { - return this.getRow(0); - } - /** * {@inheritDoc} */ diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/RowTokenizer.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/ColumnNameExtractor.java similarity index 62% rename from spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/RowTokenizer.java rename to spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/ColumnNameExtractor.java index 56cd030..36b74ed 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/RowTokenizer.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/ColumnNameExtractor.java @@ -13,20 +13,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.batch.item.excel.transform; +package org.springframework.batch.item.excel.support.rowset; -import org.springframework.batch.item.excel.RowSet; import org.springframework.batch.item.excel.Sheet; -import org.springframework.batch.item.file.transform.FieldSet; /** - * Interface that is used by framework to convert a row, represented in a String[], into a - * {@link org.springframework.batch.item.file.transform.FieldSet}. - * - * @author Marten Deinum + * Contract for extracting column names for a given {@Sheet sheet}. + * + * @author Marten Deinum * @since 0.5.0 */ -public interface RowTokenizer { +public interface ColumnNameExtractor { + + String[] getColumnNames(Sheet sheet); - FieldSet tokenize(RowSet rs); } diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSet.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSet.java new file mode 100644 index 0000000..81e5e00 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSet.java @@ -0,0 +1,114 @@ +/* + * Copyright 2006-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.excel.support.rowset; + +import org.springframework.batch.item.excel.Sheet; + +import java.util.Properties; + +/** + * Default implementation of the {@code RowSet} interface. + * + * @author Marten Deinum + * @since 0.5.0 + * + * @see org.springframework.batch.item.excel.support.rowset.DefaultRowSetFactory + */ +public class DefaultRowSet implements RowSet { + + private final Sheet sheet; + private final RowSetMetaData metaData; + + private int currentRowIndex = -1; + private String[] currentRow; + + DefaultRowSet(Sheet sheet, RowSetMetaData metaData) { + this.sheet = sheet; + this.metaData = metaData; + } + + @Override + public RowSetMetaData getMetaData() { + return metaData; + } + + @Override + public boolean next() { + currentRow = null; + currentRowIndex++; + if (currentRowIndex < sheet.getNumberOfRows()) { + currentRow = sheet.getRow(currentRowIndex); + return true; + } + return false; + } + + /** + * The current row index represents the number of rows + * into a {@link Sheet} the current line resides + */ + @Override + public int getCurrentRowIndex() { + return this.currentRowIndex; + } + + /** + * Get the data of the current row. + * + * @return a String[] for the current data + */ + @Override + public String[] getCurrentRow() { + return this.currentRow; + } + + /** + * Get the value of the given column + * + * @param idx index of the column to get, 0 based + * @return the value + * @throws java.lang.ArrayIndexOutOfBoundsException + */ + @Override + public String getColumnValue(int idx) { + return currentRow[idx]; + } + + /** + * Construct name-value pairs from the column names and string values. Null + * values are omitted. + * + * @return some properties representing the row set. + * @throws IllegalStateException if the column name meta data is not + * available. + */ + @Override + public Properties getProperties() { + final String[] names = metaData.getColumnNames(); + if (names == null) { + throw new IllegalStateException("Cannot create properties without meta data"); + } + + Properties props = new Properties(); + for (int i = 0; i < currentRow.length; i++) { + String value = currentRow[i]; + if (value != null) { + props.setProperty(names[i], value); + } + } + return props; + } +} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSetFactory.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSetFactory.java new file mode 100644 index 0000000..88e5fe3 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSetFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright 2006-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.excel.support.rowset; + +import org.springframework.batch.item.excel.Sheet; + +/** + * {@code RowSetFactory} implementation which constructs a {@code DefaultRowSet} instance and + * {@code DefaultRowSetMetaData} instance. The latter will have the {@code ColumnNameExtractor} configured + * on this factory set (default {@code RowNumberColumnNameExtractor}. + * + * @author Marten Deinum + * @since 0.5.0 + */ +public class DefaultRowSetFactory implements RowSetFactory { + + private ColumnNameExtractor columnNameExtractor = new RowNumberColumnNameExtractor(); + + @Override + public RowSet create(Sheet sheet) { + DefaultRowSetMetaData metaData = new DefaultRowSetMetaData(sheet); + metaData.setColumnNameExtractor(columnNameExtractor); + return new DefaultRowSet(sheet, metaData); + } + + public void setColumnNameExtractor(ColumnNameExtractor columnNameExtractor) { + this.columnNameExtractor = columnNameExtractor; + } +} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSetMetaData.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSetMetaData.java new file mode 100644 index 0000000..3fb02ed --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/DefaultRowSetMetaData.java @@ -0,0 +1,63 @@ +/* + * Copyright 2006-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.excel.support.rowset; + +import org.springframework.batch.item.excel.Sheet; + +/** + * Default implementation for the {@code RowSetMetaData} interface. + * + * Requires a {@code Sheet} and {@code ColumnNameExtractor} to operate correctly. + * Delegates the retrieval of the column names to the {@code ColumnNameExtractor}. + * + * @author Marten Deinum + * @since 0.5.0 + */ +public class DefaultRowSetMetaData implements RowSetMetaData { + + private final Sheet sheet; + + private ColumnNameExtractor columnNameExtractor; + + DefaultRowSetMetaData(Sheet sheet) { + this.sheet = sheet; + } + + @Override + public String[] getColumnNames() { + return columnNameExtractor.getColumnNames(sheet); + } + + @Override + public String getColumnName(int idx) { + String[] names = getColumnNames(); + return names[idx]; + } + + @Override + public int getColumnCount() { + return sheet.getNumberOfColumns(); + } + + @Override + public String getSheetName() { + return sheet.getName(); + } + + public void setColumnNameExtractor(ColumnNameExtractor columnNameExtractor) { + this.columnNameExtractor = columnNameExtractor; + } +} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowNumberColumnNameExtractor.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowNumberColumnNameExtractor.java new file mode 100644 index 0000000..2766f3b --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowNumberColumnNameExtractor.java @@ -0,0 +1,39 @@ +/* + * Copyright 2006-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.excel.support.rowset; + +import org.springframework.batch.item.excel.Sheet; + +/** + * {@code ColumnNameExtractor} which returns the values of a given row (default is 0) as the column + * names. + * + * @author Marten Deinum + * @since 0.5.0 + */ +public class RowNumberColumnNameExtractor implements ColumnNameExtractor { + + private int headerRowNumber; + + @Override + public String[] getColumnNames(final Sheet sheet) { + return sheet.getRow(headerRowNumber); + } + + public void setHeaderRowNumber(int headerRowNumber) { + this.headerRowNumber = headerRowNumber; + } +} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/ColumnToAttributeConverter.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSet.java similarity index 55% rename from spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/ColumnToAttributeConverter.java rename to spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSet.java index 12fd0ff..7ad23b5 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/ColumnToAttributeConverter.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSet.java @@ -12,30 +12,29 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */package org.springframework.batch.item.excel.transform; + */ +package org.springframework.batch.item.excel.support.rowset; + +import java.util.Properties; /** - * Convert a column name to an attribute name and vice versa. - * + * Used by the {@code org.springframework.batch.item.excel.AbstractExcelItemReader} to abstract away + * the complexities of the underlying Excel API implementations. + * * @author Marten Deinum * @since 0.5.0 */ -public interface ColumnToAttributeConverter { +public interface RowSet { - /** - * Convert a column name to an attribute name. - * - * @param column to convert - * @return the attribute name - */ - String toAttribute(String column); + RowSetMetaData getMetaData(); - /** - * Convert an attribute name to a column name. - * - * @param attribute to convert - * @return the column name - */ - String toColumn(String attribute); + boolean next(); + int getCurrentRowIndex(); + + String[] getCurrentRow(); + + String getColumnValue(int idx); + + Properties getProperties(); } diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSetFactory.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSetFactory.java new file mode 100644 index 0000000..b81a1aa --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSetFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright 2006-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.excel.support.rowset; + +import org.springframework.batch.item.excel.Sheet; + +/** + * Contract for factories which will construct a {@code RowSet} implementation. + * + * @author Marten Deinum + * @since 0.5.0 + */ +public interface RowSetFactory { + + RowSet create(Sheet sheet); +} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverter.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSetMetaData.java similarity index 61% rename from spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverter.java rename to spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSetMetaData.java index 18ccea4..944efb3 100644 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverter.java +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/RowSetMetaData.java @@ -13,24 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.batch.item.excel.transform; +package org.springframework.batch.item.excel.support.rowset; /** - * {@link ColumnToAttributeConverter} which simply returns the given value. - * + * Interface representing the the metadata associated with an Excel document. + * * @author Marten Deinum * @since 0.5.0 */ -public class PassThroughColumnToAttributeConverter implements ColumnToAttributeConverter { +public interface RowSetMetaData { - @Override - public String toAttribute(final String column) { - return column; - } + String[] getColumnNames(); - @Override - public String toColumn(final String attribute) { - return attribute; - } + String getColumnName(int idx); + int getColumnCount(); + + String getSheetName(); } diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/StaticColumnNameExtractor.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/StaticColumnNameExtractor.java new file mode 100644 index 0000000..25eda62 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/support/rowset/StaticColumnNameExtractor.java @@ -0,0 +1,41 @@ +/* + * Copyright 2006-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.batch.item.excel.support.rowset; + +import org.springframework.batch.item.excel.Sheet; + +/** + * {@code ColumnNameExtractor} implementation which returns a preset String[] to use as + * the column names. Useful for those situations in which an Excel file without a header row + * is read + * + * @author Marten Deinum + * @since 0.5.0 + */ +public class StaticColumnNameExtractor implements ColumnNameExtractor { + + private final String[] columnNames; + + public StaticColumnNameExtractor(String[] columnNames) { + this.columnNames = columnNames; + } + + @Override + public String[] getColumnNames(Sheet sheet) { + return this.columnNames; + } + +} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/DefaultRowTokenizer.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/DefaultRowTokenizer.java deleted file mode 100644 index cc1ca17..0000000 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/DefaultRowTokenizer.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2006-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.batch.item.excel.transform; - -import org.springframework.batch.item.excel.RowSet; -import org.springframework.batch.item.excel.Sheet; -import org.springframework.batch.item.file.transform.DefaultFieldSetFactory; -import org.springframework.batch.item.file.transform.FieldSet; -import org.springframework.batch.item.file.transform.FieldSetFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * {@link RowTokenizer} which assumes the column names are on the first row in the sheet. - * - * @author Marten Deinum - * @since 0.5.0 - */ -public class DefaultRowTokenizer implements RowTokenizer, InitializingBean { - - private FieldSetFactory fieldSetFactory = new DefaultFieldSetFactory(); - - private ColumnToAttributeConverter converter = new PassThroughColumnToAttributeConverter(); - - private boolean useColumnHeader = true; - - private boolean includeSheetName = false; - private String attributeForSheetName = null; - - @Override - public FieldSet tokenize(RowSet rs) { - String[] values = rs.getCurrentRow(); - - if (this.includeSheetName) { - values = StringUtils.addStringToArray(values, rs.getMetaData().getSheetName()); - } - - if (this.useColumnHeader) { - String[] names = rs.getMetaData().getColumnNames(); - if (this.includeSheetName) { - names = StringUtils.addStringToArray(names, this.attributeForSheetName); - } - for (int i = 0; i < names.length; i++) { - names[i] = this.converter.toAttribute(names[i]); - } - - return this.fieldSetFactory.create(values, names); - } else { - return this.fieldSetFactory.create(values); - } - - } - - /** - * Set the {@link org.springframework.batch.item.file.transform.FieldSetFactory} to use. The {@link org.springframework.batch.item.file.transform.DefaultFieldSetFactory} is used by default. - * - * @param fieldSetFactory to set - */ - public void setFieldSetFactory(final FieldSetFactory fieldSetFactory) { - this.fieldSetFactory = fieldSetFactory; - } - - /** - * Indication to use the column header, the default is true. - * @param useColumnHeader - */ - public void setUseColumnHeader(final boolean useColumnHeader) { - this.useColumnHeader = useColumnHeader; - } - - /** - * Set the {@link ColumnToAttributeConverter}. - * - * @param converter to set - */ - public void setConverter(final ColumnToAttributeConverter converter) { - this.converter = converter; - } - - /** - * Should the name of the sheet be included in the list of columns. Default false - * - * @param includeSheetName - */ - public void setIncludeSheetName(final boolean includeSheetName) { - this.includeSheetName = includeSheetName; - } - - /** - * When includeSheetName is true this is the name of the property used to store the name - * of the sheet. - * - * @param attributeForSheetName - * @see #setIncludeSheetName(boolean) - */ - public void setAttributeForSheetName(final String attributeForSheetName) { - this.attributeForSheetName = attributeForSheetName; - } - - public void afterPropertiesSet() throws Exception { - if (this.includeSheetName && this.useColumnHeader) { - Assert.hasText(this.attributeForSheetName, - "When using column header as attributes and including the sheetname an attribute name for the sheetname is required."); - } - } -} diff --git a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverter.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverter.java deleted file mode 100644 index 93f5d39..0000000 --- a/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2006-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.batch.item.excel.transform; - -import org.springframework.util.ObjectUtils; - -import java.util.HashMap; -import java.util.Map; - -/** - * {@link ColumnToAttributeConverter} which maps the names to columns and vice versa based on the provide mapping - * configuration. If a mapping cannot be found it returns the name as is. - * - * @author Marten Deinum - * @since 0.5.0 - */ -public class MappingColumnToAttributeConverter implements ColumnToAttributeConverter { - - private final Map mapping = new HashMap(); - - @Override - public String toAttribute(final String column) { - if (this.mapping.containsKey(column)) { - return this.mapping.get(column); - } - return column; - } - - @Override - public String toColumn(final String attribute) { - if (this.mapping.containsValue(attribute)) { - for (Map.Entry entry : this.mapping.entrySet()) { - if (ObjectUtils.nullSafeEquals(attribute, entry.getValue())) { - return entry.getKey(); - } - } - } - return attribute; - } - - public void setMappings(final Map mappings) { - this.mapping.clear(); - this.mapping.putAll(mappings); - } -} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/Player.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/Player.java new file mode 100644 index 0000000..6b145b9 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/Player.java @@ -0,0 +1,71 @@ +package org.springframework.batch.item; + +/** + * Created by in329dei on 17-9-2014. + */ +public class Player { + + private String id; + private String position; + private String lastName; + private String firstName; + private long birthYear; + private int debutYear; + private String comment; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public long getBirthYear() { + return birthYear; + } + + public void setBirthYear(long birthYear) { + this.birthYear = birthYear; + } + + public int getDebutYear() { + return debutYear; + } + + public void setDebutYear(int debutYear) { + this.debutYear = debutYear; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/AbstractExcelItemReaderTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/AbstractExcelItemReaderTests.java index 7aa99ed..3947f95 100644 --- a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/AbstractExcelItemReaderTests.java +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/AbstractExcelItemReaderTests.java @@ -22,6 +22,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.item.excel.mapping.PassThroughRowMapper; +import org.springframework.batch.item.excel.support.rowset.RowSet; import org.springframework.core.io.ClassPathResource; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.StringUtils; @@ -35,7 +36,7 @@ import static org.junit.Assert.assertEquals; */ public abstract class AbstractExcelItemReaderTests { - private final Log logger = LogFactory.getLog(this.getClass()); + protected final Log logger = LogFactory.getLog(this.getClass()); protected AbstractExcelItemReader itemReader; diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/BeanPropertyItemReaderTest.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/BeanPropertyItemReaderTest.java new file mode 100644 index 0000000..fe2c679 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/BeanPropertyItemReaderTest.java @@ -0,0 +1,71 @@ +package org.springframework.batch.item.excel; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.Player; +import org.springframework.batch.item.excel.mapping.BeanPropertyRowMapper; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Created by in329dei on 17-9-2014. + */ +public class BeanPropertyItemReaderTest { + + private MockExcelItemReader reader; + + private ExecutionContext executionContext; + + @Before + public void setup() throws Exception { + executionContext = new ExecutionContext(); + + List rows = new ArrayList(); + rows.add(new String[]{"id", "lastName", "firstName", "position", "birthYear", "debutYear"}); + rows.add( new String[]{"AbduKa00", "Abdul-Jabbar", "Karim", "rb", "1974", "1996"}); + rows.add( new String[]{"AbduRa00", "Abdullah", "Rabih", "rb", "1975", "1999"}); + MockSheet sheet = new MockSheet("players", rows); + + reader = new MockExcelItemReader(sheet); + + BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper(); + rowMapper.setTargetType(Player.class); + rowMapper.afterPropertiesSet(); + + reader.setLinesToSkip(1); // Skip first row as that is the header + reader.setRowMapper(rowMapper); + + reader.afterPropertiesSet(); + reader.open(executionContext); + } + + @Test + public void readandMapPlayers() throws Exception { + Player p1 = reader.read(); + Player p2 = reader.read(); + Player p3 = reader.read(); + assertNotNull(p1); + assertNotNull(p2); + assertNull(p3); + + // Check first player + assertEquals("AbduKa00", p1.getId()); + assertEquals("Abdul-Jabbar", p1.getLastName()); + assertEquals("Karim", p1.getFirstName()); + assertEquals("rb", p1.getPosition()); + assertEquals(1974, p1.getBirthYear()); + assertEquals(1996, p1.getDebutYear()); + // Check second player + assertEquals("AbduRa00", p2.getId()); + assertEquals("Abdullah", p2.getLastName()); + assertEquals("Rabih", p2.getFirstName()); + assertEquals("rb", p2.getPosition()); + assertEquals(1975, p2.getBirthYear()); + assertEquals(1999, p2.getDebutYear()); + } + +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/BeanPropertyWithStaticHeaderItemReaderTest.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/BeanPropertyWithStaticHeaderItemReaderTest.java new file mode 100644 index 0000000..b3c9444 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/BeanPropertyWithStaticHeaderItemReaderTest.java @@ -0,0 +1,77 @@ +package org.springframework.batch.item.excel; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.batch.item.ExecutionContext; +import org.springframework.batch.item.Player; +import org.springframework.batch.item.excel.MockExcelItemReader; +import org.springframework.batch.item.excel.MockSheet; +import org.springframework.batch.item.excel.mapping.BeanPropertyRowMapper; +import org.springframework.batch.item.excel.support.rowset.DefaultRowSet; +import org.springframework.batch.item.excel.support.rowset.DefaultRowSetFactory; +import org.springframework.batch.item.excel.support.rowset.StaticColumnNameExtractor; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Created by in329dei on 17-9-2014. + */ +public class BeanPropertyWithStaticHeaderItemReaderTest { + + private MockExcelItemReader reader; + + private ExecutionContext executionContext; + + @Before + public void setup() throws Exception { + executionContext = new ExecutionContext(); + + List rows = new ArrayList(); + rows.add( new String[]{"AbduKa00", "Abdul-Jabbar", "Karim", "rb", "1974", "1996"}); + rows.add( new String[]{"AbduRa00", "Abdullah", "Rabih", "rb", "1975", "1999"}); + MockSheet sheet = new MockSheet("players", rows); + + reader = new MockExcelItemReader(sheet); + + BeanPropertyRowMapper rowMapper = new BeanPropertyRowMapper(); + rowMapper.setTargetType(Player.class); + rowMapper.afterPropertiesSet(); + + reader.setRowMapper(rowMapper); + + DefaultRowSetFactory factory = new DefaultRowSetFactory(); + factory.setColumnNameExtractor(new StaticColumnNameExtractor(new String[]{"id", "lastName", "firstName", "position", "birthYear", "debutYear"})); + reader.setRowSetFactory(factory); + reader.afterPropertiesSet(); + reader.open(executionContext); + } + + @Test + public void readandMapPlayers() throws Exception { + Player p1 = reader.read(); + Player p2 = reader.read(); + Player p3 = reader.read(); + assertNotNull(p1); + assertNotNull(p2); + assertNull(p3); + + // Check first player + assertEquals("AbduKa00", p1.getId()); + assertEquals("Abdul-Jabbar", p1.getLastName()); + assertEquals("Karim", p1.getFirstName()); + assertEquals("rb", p1.getPosition()); + assertEquals(1974, p1.getBirthYear()); + assertEquals(1996, p1.getDebutYear()); + // Check second player + assertEquals("AbduRa00", p2.getId()); + assertEquals("Abdullah", p2.getLastName()); + assertEquals("Rabih", p2.getFirstName()); + assertEquals("rb", p2.getPosition()); + assertEquals(1975, p2.getBirthYear()); + assertEquals(1999, p2.getDebutYear()); + } + +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/MockExcelItemReader.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/MockExcelItemReader.java new file mode 100644 index 0000000..3ed2bbc --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/MockExcelItemReader.java @@ -0,0 +1,40 @@ +package org.springframework.batch.item.excel; + +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.Resource; + +import java.util.Collections; +import java.util.List; + +/** + * Created by in329dei on 17-9-2014. + */ +public class MockExcelItemReader extends AbstractExcelItemReader { + + + private final List sheets; + + public MockExcelItemReader(MockSheet sheet) { + this(Collections.singletonList(sheet)); + } + + public MockExcelItemReader(List sheets) { + this.sheets=sheets; + super.setResource(new ByteArrayResource(new byte[0])); + } + + @Override + protected Sheet getSheet(int sheet) { + return sheets.get(sheet); + } + + @Override + protected int getNumberOfSheets() { + return sheets.size(); + } + + @Override + protected void openExcelFile(Resource resource) throws Exception { + + } +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/MockSheet.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/MockSheet.java new file mode 100644 index 0000000..9501bf3 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/MockSheet.java @@ -0,0 +1,50 @@ +package org.springframework.batch.item.excel; + +import jxl.Cell; +import org.springframework.batch.item.excel.jxl.JxlUtils; + +import java.util.List; + +/** + * Sheet implementation usable for testing. Works in an {@code List} of {@xode String[]}. + * + * @author Marten Deinum + * @since 0.5.0 + */ +public class MockSheet implements Sheet { + + private final List rows; + private final String name; + + public MockSheet(String name, List rows) { + this.name = name; + this.rows = rows; + } + + @Override + public int getNumberOfRows() { + return rows.size(); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String[] getRow(int rowNumber) { + if (rowNumber < getNumberOfRows()) { + return this.rows.get(rowNumber); + } else { + return null; + } + } + + @Override + public int getNumberOfColumns() { + if (rows.isEmpty()) { + return 0; + } + return rows.get(0).length; + } +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/BeanPropertyRowMapperTest.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/BeanPropertyRowMapperTest.java new file mode 100644 index 0000000..bb89e8a --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/BeanPropertyRowMapperTest.java @@ -0,0 +1,99 @@ +package org.springframework.batch.item.excel.mapping; + +import org.junit.Test; +import org.springframework.batch.item.Player; +import org.springframework.batch.item.excel.MockSheet; +import org.springframework.batch.item.excel.support.rowset.DefaultRowSetFactory; +import org.springframework.batch.item.excel.support.rowset.RowSet; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; + +/** + * Created by in329dei on 17-9-2014. + */ +public class BeanPropertyRowMapperTest { + + @Test(expected = IllegalStateException.class) + public void givenNoNameWhenInitCompleteThenIllegalStateShouldOccur() throws Exception { + BeanPropertyRowMapper mapper = new BeanPropertyRowMapper(); + mapper.afterPropertiesSet(); + } + + @Test + public void givenAValidRowWhenMappingThenAValidPlayerShouldBeConstructed() throws Exception { + BeanPropertyRowMapper mapper = new BeanPropertyRowMapper(); + mapper.setTargetType(Player.class); + mapper.afterPropertiesSet(); + + List rows = new ArrayList(); + rows.add(new String[]{"id", "lastName", "firstName", "position", "birthYear", "debutYear"}); + rows.add( new String[]{"AbduKa00", "Abdul-Jabbar", "Karim", "rb", "1974", "1996"}); + MockSheet sheet = new MockSheet("players", rows); + + + RowSet rs = new DefaultRowSetFactory().create(sheet); + rs.next(); + rs.next(); + + Player p = mapper.mapRow(rs); + assertNotNull(p); + assertEquals("AbduKa00", p.getId()); + assertEquals("Abdul-Jabbar", p.getLastName()); + assertEquals("Karim", p.getFirstName()); + assertEquals("rb", p.getPosition()); + assertEquals(1974, p.getBirthYear()); + assertEquals(1996, p.getDebutYear()); + assertNull(p.getComment()); + + } + + @Test + public void givenAValidRowWhenMappingThenAValidPlayerShouldBeConstructedBasedOnPrototype() throws Exception { + + ApplicationContext ctx = new AnnotationConfigApplicationContext(TestConfig.class); + BeanPropertyRowMapper mapper = new BeanPropertyRowMapper(); + mapper.setPrototypeBeanName("player"); + mapper.setBeanFactory(ctx); + mapper.afterPropertiesSet(); + + List rows = new ArrayList(); + rows.add(new String[]{"id", "lastName", "firstName", "position", "birthYear", "debutYear"}); + rows.add( new String[]{"AbduKa00", "Abdul-Jabbar", "Karim", "rb", "1974", "1996"}); + MockSheet sheet = new MockSheet("players", rows); + + RowSet rs = new DefaultRowSetFactory().create(sheet); + rs.next(); + rs.next(); + Player p = mapper.mapRow(rs); + + assertNotNull(p); + assertEquals("AbduKa00", p.getId()); + assertEquals("Abdul-Jabbar", p.getLastName()); + assertEquals("Karim", p.getFirstName()); + assertEquals("rb", p.getPosition()); + assertEquals(1974, p.getBirthYear()); + assertEquals(1996, p.getDebutYear()); + assertEquals("comment from context", p.getComment()); + } + + @Configuration + public static class TestConfig { + + @Bean + @Scope(value = "prototype") + public Player player() { + Player p = new Player(); + p.setComment("comment from context"); + return p; + } + + } +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/DefaultRowMapperTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/DefaultRowMapperTests.java deleted file mode 100644 index 255fc7a..0000000 --- a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/DefaultRowMapperTests.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2006-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.batch.item.excel.mapping; - -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.batch.item.excel.RowSet; -import org.springframework.batch.item.excel.Sheet; -import org.springframework.batch.item.excel.transform.RowTokenizer; -import org.springframework.batch.item.file.mapping.FieldSetMapper; -import org.springframework.batch.item.file.transform.FieldSet; - -import static org.mockito.Matchers.any; - -/** - * Tests for {@link DefaultRowMapper}. - * @author Marten Deinum - * - */ -@RunWith(MockitoJUnitRunner.class) -public class DefaultRowMapperTests { - - @Mock - private FieldSetMapper fieldSetMapper; - - @Mock - private RowTokenizer rowTokenizer; - - @Test(expected = IllegalArgumentException.class) - public void nullRowTokenizerShouldLeadToException() throws Exception { - final DefaultRowMapper mapper = new DefaultRowMapper(); - mapper.setRowTokenizer(null); - mapper.setFieldSetMapper(this.fieldSetMapper); - mapper.afterPropertiesSet(); - } - - @Test(expected = IllegalArgumentException.class) - public void nullFieldSetMapperShouldLeadToException() throws Exception { - final DefaultRowMapper mapper = new DefaultRowMapper(); - mapper.setRowTokenizer(this.rowTokenizer); - mapper.setFieldSetMapper(null); - mapper.afterPropertiesSet(); - } - - @Test - public void foo() throws Exception { - final DefaultRowMapper mapper = new DefaultRowMapper(); - mapper.setRowTokenizer(this.rowTokenizer); - mapper.setFieldSetMapper(this.fieldSetMapper); - final FieldSet fs = Mockito.mock(FieldSet.class); - final Object result = new Object(); - Mockito.when(this.rowTokenizer.tokenize(any(RowSet.class))).thenReturn(fs); - Mockito.when(this.fieldSetMapper.mapFieldSet(fs)).thenReturn(result); - Assert.assertEquals(result, mapper.mapRow(null)); - Mockito.verify(this.rowTokenizer, Mockito.times(1)).tokenize(any(RowSet.class)); - Mockito.verify(this.fieldSetMapper, Mockito.times(1)).mapFieldSet(fs); - } - -} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapperTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapperTest.java similarity index 68% rename from spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapperTests.java rename to spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapperTest.java index dedeb01..7c4948d 100644 --- a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapperTests.java +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapperTest.java @@ -16,33 +16,31 @@ package org.springframework.batch.item.excel.mapping; import org.junit.Test; -import org.mockito.Mockito; -import org.springframework.batch.item.excel.RowSet; -import org.springframework.batch.item.excel.Sheet; +import org.springframework.batch.item.excel.MockSheet; +import org.springframework.batch.item.excel.support.rowset.DefaultRowSetFactory; +import org.springframework.batch.item.excel.support.rowset.RowSet; + +import java.util.Collections; import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.*; /** * Tests for {@link PassThroughRowMapper}. - * - * @author Marten Deinum * + * @author Marten Deinum */ -public class PassThroughRowMapperTests { +public class PassThroughRowMapperTest { private final PassThroughRowMapper rowMapper = new PassThroughRowMapper(); @Test public void mapRowShouldReturnSameValues() throws Exception { - final String[] row = new String[] { "foo", "bar", "baz" }; - Sheet sheet = mock(Sheet.class); - when(sheet.getRow(0)).thenReturn(row); - when(sheet.getNumberOfRows()).thenReturn(1); - RowSet rs = new RowSet(sheet); - assertTrue(rs.next()); + + final String[] row = new String[]{"foo", "bar", "baz"}; + MockSheet sheet = new MockSheet("mock", Collections.singletonList( row)); + RowSet rs = new DefaultRowSetFactory().create(sheet); + assertTrue(rs.next()); assertArrayEquals(row, this.rowMapper.mapRow(rs)); } diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsTest.java similarity index 85% rename from spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsTests.java rename to spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsTest.java index e395802..ef27200 100644 --- a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsTests.java +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsTest.java @@ -20,11 +20,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.batch.item.excel.AbstractExcelItemReader; import org.springframework.batch.item.excel.AbstractExcelItemReaderTests; -public class PoiItemReaderXlsTests extends AbstractExcelItemReaderTests { - - private final Log logger = LogFactory.getLog(this.getClass()); - - private PoiItemReader itemReader; +public class PoiItemReaderXlsTest extends AbstractExcelItemReaderTests { @Override protected AbstractExcelItemReader createExcelItemReader() { diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsxTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsxTest.java similarity index 94% rename from spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsxTests.java rename to spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsxTest.java index 563ec55..b0a98f1 100644 --- a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsxTests.java +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsxTest.java @@ -19,7 +19,7 @@ import org.springframework.batch.item.excel.AbstractExcelItemReader; import org.springframework.batch.item.excel.AbstractExcelItemReaderTests; import org.springframework.core.io.ClassPathResource; -public class PoiItemReaderXlsxTests extends AbstractExcelItemReaderTests { +public class PoiItemReaderXlsxTest extends AbstractExcelItemReaderTests { @Override protected void configureItemReader(AbstractExcelItemReader itemReader) { diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverterTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverterTests.java deleted file mode 100644 index d52e433..0000000 --- a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverterTests.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2006-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.batch.item.excel.transform; - -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -public class MappingColumnToAttributeConverterTests { - - private final MappingColumnToAttributeConverter converter = new MappingColumnToAttributeConverter(); - - @Before - public void setup() { - final Map mappings = new HashMap(); - mappings.put("foo", "bar1"); - mappings.put("baz", "bar2"); - mappings.put("with spaces", "noSpaces"); - this.converter.setMappings(mappings); - } - - @Test - public void convertColumnToAttribtue() { - assertEquals("bar1", this.converter.toAttribute("foo")); - assertEquals("noSpaces", this.converter.toAttribute("with spaces")); - assertEquals("not existing", this.converter.toAttribute("not existing")); - assertNull(this.converter.toAttribute(null)); - } - - @Test - public void convertAttributeToColumn() { - assertEquals("baz", this.converter.toColumn("bar2")); - assertEquals("with spaces", this.converter.toColumn("noSpaces")); - assertEquals("not existing", this.converter.toColumn("not existing")); - assertNull(this.converter.toAttribute(null)); - } - -} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverterTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverterTests.java deleted file mode 100644 index d0ec74a..0000000 --- a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverterTests.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2006-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.batch.item.excel.transform; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - -public class PassThroughColumnToAttributeConverterTests { - - private final PassThroughColumnToAttributeConverter converter = new PassThroughColumnToAttributeConverter(); - - @Test - public void columnNameShouldRemainTheSame() { - final String column = "column"; - assertEquals(column, this.converter.toAttribute(column)); - assertNull(this.converter.toAttribute(null)); - } - - @Test - public void attributeNameShouldRemainTheSame() { - final String attribute = "attribute"; - assertEquals(attribute, this.converter.toColumn(attribute)); - assertNull(this.converter.toColumn(null)); - } - -} diff --git a/spring-batch-excel/src/test/resources/log4j.xml b/spring-batch-excel/src/test/resources/log4j.xml index da237fd..8541bba 100644 --- a/spring-batch-excel/src/test/resources/log4j.xml +++ b/spring-batch-excel/src/test/resources/log4j.xml @@ -26,7 +26,7 @@ - + diff --git a/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xls b/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xls index 2a89397..a68fc84 100644 Binary files a/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xls and b/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xls differ