diff --git a/spring-batch-excel/pom.xml b/spring-batch-excel/pom.xml new file mode 100644 index 0000000..4721a62 --- /dev/null +++ b/spring-batch-excel/pom.xml @@ -0,0 +1,77 @@ + + + 4.0.0 + + org.springframewor.batch + spring-batch-excel + 1.3.0.BUILD-SNAPSHOT + + + 2.2.5.RELEASE + 2.6.12 + 3.10-FINAL + + + + + org.springframework.batch + spring-batch-core + ${spring.batch.version} + + + org.springframework.batch + spring-batch-infrastructure + ${spring.batch.version} + + + net.sourceforge.jexcelapi + jxl + ${jxl.version} + compile + true + + + org.apache.poi + poi + ${poi.version} + true + + + org.apache.poi + poi-ooxml + ${poi.version} + true + + + + + junit + junit + 4.11 + test + + + org.mockito + mockito-all + 1.9.5 + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.5.1 + + 1.6 + 1.6 + + + + + + \ No newline at end of file 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 new file mode 100644 index 0000000..c329b19 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/AbstractExcelItemReader.java @@ -0,0 +1,207 @@ +/* + * Copyright 2011-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; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +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; + +/** + * {@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} + * + * @param the type + * @author Marten Deinum + */ +public abstract class AbstractExcelItemReader extends AbstractItemCountingItemStreamItemReader implements + ResourceAwareItemReaderItemStream, InitializingBean { + + protected final Log logger = LogFactory.getLog(getClass()); + private Resource resource; + private int linesToSkip = 0; + private int currentRow = 0; + private int currentSheet = 0; + private RowMapper rowMapper; + private RowCallbackHandler skippedRowsCallback; + private boolean noInput = false; + private boolean strict = true; + + public AbstractExcelItemReader() { + super(); + this.setName(ClassUtils.getShortName(this.getClass())); + } + + @Override + protected T doRead() throws Exception { + if (this.noInput) { + return null; + } + final Sheet sheet = this.getSheet(this.currentSheet); + final String[] row = this.readRow(sheet); + if (ObjectUtils.isEmpty(row)) { + this.currentSheet++; + if (this.currentSheet >= this.getNumberOfSheets()) { + if (logger.isDebugEnabled() ) { + logger.debug("No more sheets in '" + this.resource.getDescription() + "'."); + } + return null; + } else { + this.currentRow = 0; + this.openSheet(); + return this.doRead(); + } + } else { + try { + return this.rowMapper.mapRow(sheet, row, this.currentRow); + } catch (final Exception e) { + throw new ExcelFileParseException("Exception parsing Excel file.", e, this.resource.getDescription(), + sheet.getName(), this.currentRow, row); + } + } + } + + @Override + protected void doOpen() throws Exception { + Assert.notNull(this.resource, "Input resource must be set"); + this.noInput = true; + if (!this.resource.exists()) { + if (this.strict) { + throw new IllegalStateException("Input resource must exist (reader is in 'strict' mode): " + + this.resource); + } + logger.warn("Input resource does not exist '"+this.resource.getDescription()+"'."); + return; + } + + if (!this.resource.isReadable()) { + if (this.strict) { + 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()+"'."); + return; + } + + this.noInput = false; + this.openExcelFile(this.resource); + this.openSheet(); + if (logger.isDebugEnabled()) { + logger.debug("Opened workbook ["+this.resource.getFilename()+"] with "+this.getNumberOfSheets()+" sheets."); + } + } + + private String[] readRow(final Sheet sheet) { + this.currentRow++; + if (this.currentRow < sheet.getNumberOfRows()) { + return sheet.getRow(this.currentRow); + } + return null; + } + + private void openSheet() { + final Sheet sheet = this.getSheet(this.currentSheet); + if (logger.isDebugEnabled()) { + logger.debug("Opening sheet "+sheet.getName()+"."); + } + for (int i = 0; i < this.linesToSkip; i++) { + final String[] row = this.readRow(sheet); + if (this.skippedRowsCallback != null) { + this.skippedRowsCallback.handleRow(sheet, row); + } + } + if (logger.isDebugEnabled()) { + logger.debug("Openend sheet "+sheet.getName()+", with "+sheet.getNumberOfRows()+" rows."); + } + + } + + @Override + protected final void doClose() throws Exception { + doCloseWorkbook(); + if (getResource() != null) { + try { + InputStream is = getResource().getInputStream(); + is.close(); + } catch (IOException ioe) { + logger.warn("Exception whilst obtaining or closing the inputstream.", ioe); + } + } + } + + /** + * Method which can be overriden by subclasses to do cleanup additional resources. + * + * @throws Exception + */ + protected void doCloseWorkbook() throws Exception { + } + + protected Resource getResource() { + return this.resource; + } + + public void setResource(final Resource resource) { + this.resource = resource; + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(this.rowMapper, "RowMapper must be set"); + } + + /** + * Set the number of lines to skip. This number is applied to all worksheet + * in the excel file! default to 0 + * + * @param linesToSkip + */ + public void setLinesToSkip(final int linesToSkip) { + this.linesToSkip = linesToSkip; + } + + protected abstract Sheet getSheet(int sheet); + + protected abstract int getNumberOfSheets(); + + protected abstract void openExcelFile(Resource resource) throws Exception; + + /** + * In strict mode the reader will throw an exception on + * {@link #open(org.springframework.batch.item.ExecutionContext)} if the input resource does not exist. + * + * @param strict true by default + */ + public void setStrict(final boolean strict) { + this.strict = strict; + } + + public void setRowMapper(final RowMapper rowMapper) { + this.rowMapper = rowMapper; + } + + 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 new file mode 100644 index 0000000..21283b2 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/ExcelFileParseException.java @@ -0,0 +1,75 @@ +/* + * Copyright 2011-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; + +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 + * simply dependencies to make it is generic as possible. + * + * @author Marten Deinum + * + */ +public class ExcelFileParseException extends ParseException { + + /** + * + */ + private static final long serialVersionUID = -3939056060545496492L; + + private final String filename; + private final String sheet; + private final String[] row; + private final int rowNumber; + + /** + * 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 rowNumber the row number in the current sheet + * @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) { + super(message, cause); + this.filename = filename; + this.sheet = sheet; + this.rowNumber = rowNumber; + this.row = row; + } + + public String getFilename() { + return this.filename; + } + + public String getSheet() { + return this.sheet; + } + + public int getRowNumber() { + return this.rowNumber; + } + + public String[] getRow() { + return this.row; + } + +} 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 new file mode 100644 index 0000000..450e611 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowCallbackHandler.java @@ -0,0 +1,28 @@ +/* + * Copyright 2011-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; + +/** + * Callback to handle skipped lines. Useful for header/footer processing. + * + * @author Marten Deinum + */ +public interface RowCallbackHandler { + + void handleRow(Sheet sheet, String[] row); + +} 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 new file mode 100644 index 0000000..6001450 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/RowMapper.java @@ -0,0 +1,40 @@ +/* + * Copyright 2011-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; + +/** + * Map rows from an excel sheet to an object. + * + * @author Marten Deinum + * + * @param + */ +public interface RowMapper { + + /** + * 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 sheet the current sheet + * @param row to be mapped + * @param rowNum of the current row + * @return mapped object of type T + * @throws Exception if error occured while parsing. + */ + T mapRow(Sheet sheet, String[] row, int rowNum) throws Exception; + +} 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 new file mode 100644 index 0000000..248cc6f --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/Sheet.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011-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; + +/** + * Interface to wrap different Excel implementations like JExcel, JXL or Apache POI. + * + * @author Marten Deinum + * + */ +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 new file mode 100644 index 0000000..4215160 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlItemReader.java @@ -0,0 +1,73 @@ + +/* + * Copyright 2011-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.jxl; + +import jxl.Workbook; +import jxl.read.biff.WorkbookParser; +import org.springframework.batch.item.excel.AbstractExcelItemReader; +import org.springframework.batch.item.excel.Sheet; +import org.springframework.core.io.Resource; +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 + * + * @param the type + */ +public class JxlItemReader extends AbstractExcelItemReader { + + private Workbook workbook; + + public JxlItemReader() { + super(); + this.setName(ClassUtils.getShortName(JxlItemReader.class)); + } + + @Override + protected void openExcelFile(final Resource resource) throws Exception { + this.workbook = WorkbookParser.getWorkbook(resource.getInputStream()); + } + + @Override + protected void doCloseWorkbook() throws Exception { + if (this.workbook != null) { + this.workbook.close(); + } + } + + @Override + protected Sheet getSheet(final int sheet) { + if (sheet < this.workbook.getNumberOfSheets()) { + return new JxlSheet(this.workbook.getSheet(sheet)); + } + return null; + } + + @Override + protected int getNumberOfSheets() { + if (this.workbook == null) { + throw new IllegalStateException("Workbook file not ready for reading!"); + } + return this.workbook.getNumberOfSheets(); + } + +} 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 new file mode 100644 index 0000000..9867cbb --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlSheet.java @@ -0,0 +1,79 @@ + +/* + * Copyright 2011-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.jxl; + +import jxl.Cell; +import org.springframework.batch.item.excel.Sheet; + +/** + * {@link org.springframework.batch.item.excel.Sheet} implementation for JXL. + * + * @author Marten Deinum + * + */ +public class JxlSheet implements Sheet { + + private final jxl.Sheet delegate; + + /** + * Constructor which takes the delegate sheet. + * + * @param delegate the JXL sheet + */ + JxlSheet(final jxl.Sheet delegate) { + super(); + this.delegate = delegate; + } + + /** + * {@inheritDoc} + */ + public int getNumberOfRows() { + return this.delegate.getRows(); + } + + /** + * {@inheritDoc} + */ + public String[] getHeader() { + return this.getRow(0); + } + + /** + * {@inheritDoc} + */ + public String[] getRow(final int rowNumber) { + final Cell[] row = this.delegate.getRow(rowNumber); + return JxlUtils.extractContents(row); + } + + /** + * {@inheritDoc} + */ + public String getName() { + return this.delegate.getName(); + } + + /** + * {@inheritDoc} + */ + public int getNumberOfColumns() { + return this.delegate.getColumns(); + } + +} 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 new file mode 100644 index 0000000..6f67c8f --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/jxl/JxlUtils.java @@ -0,0 +1,95 @@ +/* + * Copyright 2011-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.jxl; + +import jxl.Cell; +import jxl.Workbook; +import org.springframework.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class containing utility methods to work with JXL. + * + * @author Marten Deinum + * + */ +public final class JxlUtils { + + /** 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) + */ + public static boolean isEmpty(final Cell cell) { + return cell == null || !StringUtils.hasText(cell.getContents()); + } + + /** + * Check if the given row (Cell[]) is empty. It is considered empty when the row is null, the array is empty or all + * the cells in the row are empty. + * + * @param row to check + * @return true/false + */ + public static boolean isEmpty(final Cell[] row) { + if (row == null || row.length == 0) { + return true; + } + for (final Cell cell : row) { + if (!isEmpty(cell)) { + return false; + } + } + return true; + } + + /** + * Check if the given workbook has any sheets. + * + * @param workbook to check + * @return true/false + */ + public static boolean hasSheets(final Workbook workbook) { + return workbook != null && workbook.getNumberOfSheets() > 0; + } + + /** + * Extract the content from the given row. + * + * @param row the row + * @return the content as String[] + */ + public static String[] extractContents(final Cell[] row) { + final List values = new ArrayList(); + for (final Cell cell : row) { + if (!isEmpty(cell)) { + values.add(cell.getColumn(), cell.getContents()); + } else { + values.add(cell.getColumn(), ""); + } + } + return values.toArray(new String[values.size()]); + } +} 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 new file mode 100644 index 0000000..1155445 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/DefaultRowMapper.java @@ -0,0 +1,62 @@ + +/* + * 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.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 + * + * @param + */ +public class DefaultRowMapper implements RowMapper, InitializingBean { + + private RowTokenizer rowTokenizer = new DefaultRowTokenizer(); + private FieldSetMapper fieldSetMapper; + + public T mapRow(final Sheet sheet, final String[] row, final int rowNum) throws Exception { + return this.fieldSetMapper.mapFieldSet(this.rowTokenizer.tokenize(sheet, row)); + } + + 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; + } + + 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 new file mode 100644 index 0000000..ef1cc36 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapper.java @@ -0,0 +1,34 @@ +/* + * 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.Sheet; + +/** + * Pass through {@link RowMapper} useful for passing the orginal String[] + * back directly rather than a mapped object. + * + * @author Marten Deinum + * + */ +public class PassThroughRowMapper implements RowMapper { + + public String[] mapRow(final Sheet sheet, final String[] row, final int rowNum) throws Exception { + return row; + } + +} 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 new file mode 100644 index 0000000..90c4eec --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiItemReader.java @@ -0,0 +1,53 @@ +/* + * 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.poi; + +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.springframework.batch.item.excel.AbstractExcelItemReader; +import org.springframework.batch.item.excel.Sheet; +import org.springframework.core.io.Resource; + +/** + * {@link org.springframework.batch.item.ItemReader} implementation which uses apache POI 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 + * + * @param the type + */ +public class PoiItemReader extends AbstractExcelItemReader { + + private Workbook workbook; + + @Override + protected Sheet getSheet(final int sheet) { + return new PoiSheet(this.workbook.getSheetAt(sheet)); + } + + @Override + protected int getNumberOfSheets() { + return this.workbook.getNumberOfSheets(); + } + + @Override + protected void openExcelFile(final Resource resource) throws Exception { + this.workbook = WorkbookFactory.create(resource.getInputStream()); + } + +} 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 new file mode 100644 index 0000000..ea38de3 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/poi/PoiSheet.java @@ -0,0 +1,109 @@ +/* + * Copyright 2011-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.poi; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.springframework.batch.item.excel.Sheet; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * Sheet implementation for Apache POI. + * + * @author Marten Deinum + * + */ +public class PoiSheet implements Sheet { + + private final org.apache.poi.ss.usermodel.Sheet delegate; + + /** + * Constructor which takes the delegate sheet. + * + * @param delegate the apache POI sheet + */ + PoiSheet(final org.apache.poi.ss.usermodel.Sheet delegate) { + super(); + this.delegate = delegate; + } + + /** + * {@inheritDoc} + */ + public int getNumberOfRows() { + return this.delegate.getLastRowNum() + 1; + } + + /** + * {@inheritDoc} + */ + public String getName() { + return this.delegate.getSheetName(); + } + + /** + * {@inheritDoc} + */ + public String[] getRow(final int rowNumber) { + if (rowNumber > this.delegate.getLastRowNum()) { + return null; + } + final Row row = this.delegate.getRow(rowNumber); + final List cells = new LinkedList(); + + final Iterator cellIter = row.iterator(); + while (cellIter.hasNext()) { + final Cell cell = cellIter.next(); + 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; + default: + throw new IllegalArgumentException("Cannot handle cells of type " + cell.getCellType()); + } + } + return cells.toArray(new String[cells.size()]); + } + + /** + * {@inheritDoc} + */ + public String[] getHeader() { + return this.getRow(0); + } + + /** + * {@inheritDoc} + */ + public int getNumberOfColumns() { + final String[] columns = this.getHeader(); + if (columns != null) { + return columns.length; + } + return 0; + } +} 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/transform/ColumnToAttributeConverter.java new file mode 100644 index 0000000..1779c7b --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/ColumnToAttributeConverter.java @@ -0,0 +1,40 @@ +/* + * Copyright 2011-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; + +/** + * Convert a column name to an attribute name and vice versa. + * + * @author Marten Deinum + */ +public interface ColumnToAttributeConverter { + + /** + * Convert a column name to an attribute name. + * + * @param column to convert + * @return the attribute name + */ + String toAttribute(String column); + + /** + * Convert an attribute name to a column name. + * + * @param attribute to convert + * @return the column name + */ + String toColumn(String attribute); + +} 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 new file mode 100644 index 0000000..56463b1 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/DefaultRowTokenizer.java @@ -0,0 +1,106 @@ +/* + * Copyright 2011-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.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 + */ +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; + + public FieldSet tokenize(final Sheet sheet, final String[] row) { + String[] values = new String[sheet.getNumberOfColumns()]; + System.arraycopy(row, 0, values, 0, row.length); + + if (this.includeSheetName) { + values = StringUtils.addStringToArray(values, sheet.getName()); + } + + if (this.useColumnHeader) { + String[] names = sheet.getHeader(); + 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; + } + + public void setIncludeSheetName(final boolean includeSheetName) { + this.includeSheetName = includeSheetName; + } + + 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 new file mode 100644 index 0000000..649454a --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2011-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 + */ +public class MappingColumnToAttributeConverter implements ColumnToAttributeConverter { + + private final Map mapping = new HashMap(); + + public String toAttribute(final String column) { + if (this.mapping.containsKey(column)) { + return this.mapping.get(column); + } + return column; + } + + 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/main/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverter.java b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverter.java new file mode 100644 index 0000000..398e93a --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverter.java @@ -0,0 +1,33 @@ +/* + * Copyright 2011-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; + +/** + * {@link ColumnToAttributeConverter} which simply returns the given value. + * + * @author Marten Deinum + */ +public class PassThroughColumnToAttributeConverter implements ColumnToAttributeConverter { + + public String toAttribute(final String column) { + return column; + } + + public String toColumn(final String attribute) { + return attribute; + } + +} 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/transform/RowTokenizer.java new file mode 100644 index 0000000..8603989 --- /dev/null +++ b/spring-batch-excel/src/main/java/org/springframework/batch/item/excel/transform/RowTokenizer.java @@ -0,0 +1,30 @@ +/* + * Copyright 2011-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.Sheet; +import org.springframework.batch.item.file.transform.FieldSet; + +/** + * Interface that is used by framework to convert a Cell[] into a {@link org.springframework.batch.item.file.transform.FieldSet}. + * + * @author Marten Deinum + */ + +public interface RowTokenizer { + + FieldSet tokenize(Sheet sheet, String[] row); +} 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 new file mode 100644 index 0000000..95ae28c --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/AbstractExcelItemReaderTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2011-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; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.After; +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.core.io.ClassPathResource; +import org.springframework.util.StringUtils; + +import static org.junit.Assert.assertEquals; + +/** + * Base class for testing Excel based item readers. + * + * @author Marten Deinum + */ +public abstract class AbstractExcelItemReaderTests { + + private final Log logger = LogFactory.getLog(this.getClass()); + + protected AbstractExcelItemReader itemReader; + + @Before + public void setup() throws Exception { + this.itemReader = createExcelItemReader(); + this.itemReader.setLinesToSkip(1); //First line is column names + this.itemReader.setResource(new ClassPathResource("org/springframework/batch/item/excel/player.xls")); + this.itemReader.setRowMapper(new PassThroughRowMapper()); + this.itemReader.setSkippedRowsCallback(new RowCallbackHandler() { + + public void handleRow(final Sheet sheet, final String[] row) { + logger.info("Skipping: " + StringUtils.arrayToCommaDelimitedString(row)); + } + }); + configureItemReader(this.itemReader); + this.itemReader.afterPropertiesSet(); + this.itemReader.open(new ExecutionContext()); + } + + protected void configureItemReader(AbstractExcelItemReader itemReader) { + } + + @After + public void after() throws Exception { + this.itemReader.close(); + } + + @Test + public void readExcelFile() throws Exception { + assertEquals(3, this.itemReader.getNumberOfSheets()); + String[] row = null; + do { + row = (String[]) this.itemReader.read(); + this.logger.debug("Read: "+ StringUtils.arrayToCommaDelimitedString(row)); + } while (row != null); + } + + @Test(expected = IllegalArgumentException.class) + public void testRequiredProperties() throws Exception { + final AbstractExcelItemReader reader = createExcelItemReader(); + reader.afterPropertiesSet(); + } + + protected abstract AbstractExcelItemReader createExcelItemReader(); + +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/jxl/JxlItemReaderTest.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/jxl/JxlItemReaderTest.java new file mode 100644 index 0000000..54b8aa1 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/jxl/JxlItemReaderTest.java @@ -0,0 +1,32 @@ +/* + * Copyright 2011-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.jxl; + +import org.springframework.batch.item.excel.AbstractExcelItemReader; +import org.springframework.batch.item.excel.AbstractExcelItemReaderTests; + +/** + * Test + */ +public class JxlItemReaderTest extends AbstractExcelItemReaderTests { + + @Override + protected AbstractExcelItemReader createExcelItemReader() { + return new JxlItemReader(); + } + +} diff --git a/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/jxl/JxlUtilsTests.java b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/jxl/JxlUtilsTests.java new file mode 100644 index 0000000..3e4f150 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/jxl/JxlUtilsTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2011-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.jxl; + +import jxl.Cell; +import jxl.Workbook; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +/** + * Tests for {@link org.springframework.batch.item.excel.jxl.JxlUtils}. + * + * @author Marten Deinum + * + */ +public class JxlUtilsTests { + + private final Cell cell1 = Mockito.mock(Cell.class); + private final Cell cell2 = Mockito.mock(Cell.class); + private final Cell cell3 = Mockito.mock(Cell.class); + private final Cell cell4 = Mockito.mock(Cell.class); + + private final Workbook workbook = Mockito.mock(Workbook.class); + + @Before + public void setup() { + Mockito.when(this.cell1.getContents()).thenReturn("foo"); + Mockito.when(this.cell2.getContents()).thenReturn(" "); + Mockito.when(this.cell3.getContents()).thenReturn(""); + Mockito.when(this.cell4.getContents()).thenReturn(null); + } + + /** + * Test the {@link org.springframework.batch.item.excel.jxl.JxlUtils#isEmpty( jxl.Cell)} method. + */ + @Test + public void checkIfCellsAreEmpty() { + Assert.assertFalse("Cell1 should not be empty", JxlUtils.isEmpty(this.cell1)); + Assert.assertTrue("Cell2 should be empty", JxlUtils.isEmpty(this.cell2)); + Assert.assertTrue("Cell3 should be empty", JxlUtils.isEmpty(this.cell3)); + Assert.assertTrue("Cell4 should be empty", JxlUtils.isEmpty(this.cell4)); + Assert.assertTrue("[null] should be empty", JxlUtils.isEmpty((Cell) null)); + } + + /** + * Test the {@link JxlUtils#isEmpty( jxl.Cell[])} method. + */ + @Test + public void checkIfRowIsEmpty() { + Assert.assertTrue("[null] should be empty", JxlUtils.isEmpty((Cell[]) null)); + Assert.assertTrue("[null] should be empty", JxlUtils.isEmpty(new Cell[0])); + Assert.assertFalse("Cell[]1 should not be empty", + JxlUtils.isEmpty(new Cell[]{this.cell1, this.cell2, this.cell3})); + Assert.assertTrue("Cell[]2 should be empty", JxlUtils.isEmpty(new Cell[]{this.cell2, this.cell3, null})); + } + + /** + * Test the {@link JxlUtils#hasSheets( jxl.Workbook)} method. + */ + @Test + public void checkIfWorkbookHasSheets() { + Assert.assertFalse("[null] doesn't have sheets.", JxlUtils.hasSheets(null)); + Mockito.when(this.workbook.getNumberOfSheets()).thenReturn(5); + Assert.assertTrue("Workbook should have sheets.", JxlUtils.hasSheets(this.workbook)); + Mockito.when(this.workbook.getNumberOfSheets()).thenReturn(0); + Assert.assertFalse("Workbook shouldn't have sheets.", JxlUtils.hasSheets(this.workbook)); + + } + +} 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 new file mode 100644 index 0000000..c86cd49 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/DefaultRowMapperTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2011-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.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(Sheet.class), any(String[].class))).thenReturn(fs); + Mockito.when(this.fieldSetMapper.mapFieldSet(fs)).thenReturn(result); + Assert.assertEquals(result, mapper.mapRow(null, null, 0)); + Mockito.verify(this.rowTokenizer, Mockito.times(1)).tokenize(any(Sheet.class), any(String[].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/PassThroughRowMapperTests.java new file mode 100644 index 0000000..77fdbf6 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/mapping/PassThroughRowMapperTests.java @@ -0,0 +1,45 @@ +/* + * Copyright 2011-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.Test; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertNull; + +/** + * Tests for {@link PassThroughRowMapper}. + * + * @author Marten Deinum + * + */ +public class PassThroughRowMapperTests { + + private final PassThroughRowMapper rowMapper = new PassThroughRowMapper(); + + @Test + public void mapRowShouldReturnSameValues() throws Exception { + final String[] row = new String[] { "foo", "bar", "baz" }; + + assertArrayEquals(row, this.rowMapper.mapRow(null, row, 0)); + } + + @Test + public void mapRowShouldReturnNull() throws Exception { + assertNull(this.rowMapper.mapRow(null, null, 0)); + } + +} 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/PoiItemReaderXlsTests.java new file mode 100644 index 0000000..3831721 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsTests.java @@ -0,0 +1,34 @@ +/* + * Copyright 2011-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.poi; + +import org.apache.commons.logging.Log; +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; + + @Override + protected AbstractExcelItemReader createExcelItemReader() { + return new PoiItemReader(); + } + +} 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/PoiItemReaderXlsxTests.java new file mode 100644 index 0000000..a6e613a --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/poi/PoiItemReaderXlsxTests.java @@ -0,0 +1,33 @@ +/* + * Copyright 2011-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.poi; + +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 { + + @Override + protected void configureItemReader(AbstractExcelItemReader itemReader) { + itemReader.setResource(new ClassPathResource("org/springframework/batch/item/excel/player.xlsx")); + } + + @Override + protected AbstractExcelItemReader createExcelItemReader() { + return new PoiItemReader(); + } +} 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 new file mode 100644 index 0000000..e7f9ba4 --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/MappingColumnToAttributeConverterTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2011-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 new file mode 100644 index 0000000..32932ca --- /dev/null +++ b/spring-batch-excel/src/test/java/org/springframework/batch/item/excel/transform/PassThroughColumnToAttributeConverterTests.java @@ -0,0 +1,41 @@ +/* + * Copyright 2011-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 new file mode 100644 index 0000000..8ae1229 --- /dev/null +++ b/spring-batch-excel/src/test/resources/log4j.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/games.xls b/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/games.xls new file mode 100644 index 0000000..a61f016 Binary files /dev/null and b/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/games.xls differ 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 new file mode 100644 index 0000000..6d5b08d Binary files /dev/null and b/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xls differ diff --git a/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xlsx b/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xlsx new file mode 100644 index 0000000..358688f Binary files /dev/null and b/spring-batch-excel/src/test/resources/org/springframework/batch/item/excel/player.xlsx differ