XlsTable.java

  1. /*
  2.  *
  3.  * The DbUnit Database Testing Framework
  4.  * Copyright (C)2002-2004, DbUnit.org
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  *
  20.  */
  21. package org.dbunit.dataset.excel;

  22. import java.math.BigDecimal;
  23. import java.text.DecimalFormat;
  24. import java.text.DecimalFormatSymbols;
  25. import java.util.ArrayList;
  26. import java.util.Date;
  27. import java.util.List;
  28. import java.util.TimeZone;

  29. import org.apache.poi.ss.usermodel.Cell;
  30. import org.apache.poi.ss.usermodel.CellStyle;
  31. import org.apache.poi.ss.usermodel.CellType;
  32. import org.apache.poi.ss.usermodel.DateUtil;
  33. import org.apache.poi.ss.usermodel.Row;
  34. import org.apache.poi.ss.usermodel.Sheet;
  35. import org.dbunit.dataset.AbstractTable;
  36. import org.dbunit.dataset.Column;
  37. import org.dbunit.dataset.DataSetException;
  38. import org.dbunit.dataset.DefaultTableMetaData;
  39. import org.dbunit.dataset.ITableMetaData;
  40. import org.dbunit.dataset.datatype.DataType;
  41. import org.dbunit.dataset.datatype.DataTypeException;
  42. import org.slf4j.Logger;
  43. import org.slf4j.LoggerFactory;

  44. /**
  45.  * @author Manuel Laflamme
  46.  * @author Last changed by: $Author$
  47.  * @version $Revision$ $Date$
  48.  * @since Feb 21, 2003
  49.  */
  50. class XlsTable extends AbstractTable
  51. {

  52.     /**
  53.      * Logger for this class
  54.      */
  55.     private static final Logger logger = LoggerFactory.getLogger(XlsTable.class);

  56.     private final ITableMetaData _metaData;
  57.     private final Sheet _sheet;
  58.    
  59.     private final DecimalFormatSymbols symbols = new DecimalFormatSymbols();
  60.    

  61.     public XlsTable(String sheetName, Sheet sheet) throws DataSetException
  62.     {
  63.         int rowCount = sheet.getLastRowNum();
  64.         if (rowCount >= 0 && sheet.getRow(0) != null)
  65.         {
  66.             _metaData = createMetaData(sheetName, sheet.getRow(0));
  67.         }
  68.         else
  69.         {
  70.             _metaData = new DefaultTableMetaData(sheetName, new Column[0]);
  71.         }

  72.         _sheet = sheet;
  73.        
  74.         // Needed for later "BigDecimal"/"Number" conversion
  75.         symbols.setDecimalSeparator('.');
  76.     }

  77.     static ITableMetaData createMetaData(String tableName, Row sampleRow)
  78.     {
  79.         logger.debug("createMetaData(tableName={}, sampleRow={}) - start", tableName, sampleRow);

  80.         List columnList = new ArrayList();
  81.         for (int i = 0; ; i++)
  82.         {
  83.             Cell cell = sampleRow.getCell(i);
  84.             if (cell == null)
  85.             {
  86.                 break;
  87.             }

  88.             String columnName = cell.getRichStringCellValue().getString();
  89.             if (columnName != null)
  90.             {
  91.                 columnName = columnName.trim();
  92.             }
  93.            
  94.             // Bugfix for issue ID 2818981 - if a cell has a formatting but no name also ignore it
  95.             if(columnName.length()<=0)
  96.             {
  97.                 logger.debug("The column name of column # {} is empty - will skip here assuming the last column was reached", i);
  98.                 break;
  99.             }
  100.            
  101.             Column column = new Column(columnName, DataType.UNKNOWN);
  102.             columnList.add(column);
  103.         }
  104.         Column[] columns = (Column[])columnList.toArray(new Column[0]);
  105.         return new DefaultTableMetaData(tableName, columns);
  106.     }

  107.     ////////////////////////////////////////////////////////////////////////////
  108.     // ITable interface

  109.     public int getRowCount()
  110.     {
  111.         logger.debug("getRowCount() - start");

  112.         return _sheet.getLastRowNum();
  113.     }

  114.     public ITableMetaData getTableMetaData()
  115.     {
  116.         logger.debug("getTableMetaData() - start");

  117.         return _metaData;
  118.     }

  119.     public Object getValue(int row, String column) throws DataSetException
  120.     {
  121.         logger.debug("getValue(row={}, columnName={}) - start", row, column);

  122.         assertValidRowIndex(row);

  123.         int columnIndex = getColumnIndex(column);
  124.         Cell cell = _sheet.getRow(row + 1).getCell(columnIndex);
  125.         if (cell == null)
  126.         {
  127.             return null;
  128.         }

  129.         CellType type = cell.getCellType();
  130.         switch (type)
  131.         {
  132.             case NUMERIC:
  133.                 CellStyle style = cell.getCellStyle();
  134.                 if (DateUtil.isCellDateFormatted(cell))
  135.                 {
  136.                     return getDateValue(cell);
  137.                 }
  138.                 else if(XlsDataSetWriter.DATE_FORMAT_AS_NUMBER_DBUNIT.equals(style.getDataFormatString()))
  139.                 {
  140.                     // The special dbunit date format
  141.                     return getDateValueFromJavaNumber(cell);
  142.                 }
  143.                 else
  144.                 {
  145.                     return getNumericValue(cell);
  146.                 }

  147.             case STRING:
  148.                 return cell.getRichStringCellValue().getString();

  149.             case FORMULA:
  150.                 throw new DataTypeException("Formula not supported at row=" +
  151.                         row + ", column=" + column);

  152.             case BLANK:
  153.                 return null;

  154.             case BOOLEAN:
  155.                 return cell.getBooleanCellValue() ? Boolean.TRUE : Boolean.FALSE;

  156.             case ERROR:
  157.                 throw new DataTypeException("Error at row=" + row +
  158.                         ", column=" + column);

  159.             default:
  160.                 throw new DataTypeException("Unsupported type at row=" + row +
  161.                         ", column=" + column);
  162.         }
  163.     }
  164.    
  165.     protected Object getDateValueFromJavaNumber(Cell cell)
  166.     {
  167.         logger.debug("getDateValueFromJavaNumber(cell={}) - start", cell);
  168.        
  169.         double numericValue = cell.getNumericCellValue();
  170.         BigDecimal numericValueBd = new BigDecimal(String.valueOf(numericValue));
  171.         numericValueBd = stripTrailingZeros(numericValueBd);
  172.         return numericValueBd.longValue();
  173.     }
  174.    
  175.     protected Object getDateValue(Cell cell)
  176.     {
  177.         logger.debug("getDateValue(cell={}) - start", cell);
  178.        
  179.         double numericValue = cell.getNumericCellValue();
  180.         Date date = DateUtil.getJavaDate(numericValue);
  181.         return date.getTime();
  182.        
  183.         //TODO use a calendar for XLS Date objects when it is supported better by POI
  184. //        HSSFCellStyle style = cell.getCellStyle();
  185. //        HSSFDataFormatter formatter = new HSSFDataFormatter();
  186. //        Format f = formatter.createFormat(cell);
  187. //      String formatted = fomatter.formatCellValue(cell);
  188. //System.out.println("###"+formatted);
  189. //        Date dateValue = cell.getDateCellValue();
  190.     }

  191.     /**
  192.      * Removes all trailing zeros from the end of the given BigDecimal value
  193.      * up to the decimal point.
  194.      * @param value The value to be stripped
  195.      * @return The value without trailing zeros
  196.      */
  197.     private BigDecimal stripTrailingZeros(BigDecimal value)
  198.     {
  199.         if(value.scale()<=0){
  200.             return value;
  201.         }
  202.        
  203.         String valueAsString = String.valueOf(value);
  204.         int idx = valueAsString.indexOf(".");
  205.         if(idx==-1){
  206.             return value;
  207.         }
  208.        
  209.         for(int i=valueAsString.length()-1; i>idx; i--){
  210.             if(valueAsString.charAt(i)=='0'){
  211.                 valueAsString = valueAsString.substring(0, i);
  212.             }
  213.             else if(valueAsString.charAt(i)=='.'){
  214.                 valueAsString = valueAsString.substring(0, i);
  215.                 // Stop when decimal point is reached
  216.                 break;
  217.             }
  218.             else{
  219.                 break;
  220.             }
  221.         }
  222.         BigDecimal result = new BigDecimal(valueAsString);
  223.         return result;
  224.     }
  225.    
  226.     protected BigDecimal getNumericValue(Cell cell)
  227.     {
  228.         logger.debug("getNumericValue(cell={}) - start", cell);

  229.         String formatString = cell.getCellStyle().getDataFormatString();
  230.         String resultString = null;
  231.         double cellValue = cell.getNumericCellValue();

  232.         if((formatString != null))
  233.         {
  234.             if(!formatString.equals("General") && !formatString.equals("@")) {
  235.                 logger.debug("formatString={}", formatString);
  236.                 DecimalFormat nf = new DecimalFormat(formatString, symbols);
  237.                 resultString = nf.format(cellValue);
  238.             }
  239.         }
  240.        
  241.         BigDecimal result;
  242.         if(resultString != null) {
  243.             try {
  244.                 result = new BigDecimal(resultString);
  245.             }
  246.             catch(NumberFormatException e) {
  247.                 logger.debug("Exception occurred while trying create a BigDecimal. value={}", resultString);
  248.                 // Probably was not a BigDecimal format retrieved from the excel. Some
  249.                 // date formats are not yet recognized by HSSF as DateFormats so that
  250.                 // we could get here.
  251.                 result = toBigDecimal(cellValue);
  252.             }
  253.         }
  254.         else {
  255.             result = toBigDecimal(cellValue);
  256.         }
  257.         return result;
  258.     }

  259.     /**
  260.      * @param cellValue
  261.      * @return
  262.      * @since 2.4.6
  263.      */
  264.     private BigDecimal toBigDecimal(double cellValue)
  265.     {
  266.         String resultString = String.valueOf(cellValue);
  267.         // To ensure that intergral numbers do not have decimal point and trailing zero
  268.         // (to restore backward compatibility and provide a string representation consistent with Excel)
  269.         if (resultString.endsWith(".0")) {
  270.             resultString=resultString.substring(0,resultString.length()-2);
  271.         }
  272.         BigDecimal result = new BigDecimal(resultString);
  273.         return result;
  274.        
  275.     }

  276.     public String toString()
  277.     {
  278.         StringBuilder sb = new StringBuilder();
  279.         sb.append(getClass().getName()).append("[");
  280.         sb.append("_metaData=").append(
  281.                 this._metaData == null ? "null" : this._metaData.toString());
  282.         sb.append(", _sheet=").append(
  283.                 this._sheet == null ? "null" : "" + this._sheet);
  284.         sb.append(", symbols=").append(
  285.                 this.symbols == null ? "null" : "" + this.symbols);
  286.         sb.append("]");
  287.         return sb.toString();
  288.     }
  289. }