package net.objectlab.kit.util.excel;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.AreaReference;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.*;
public class Excel {
private Workbook workbook;
public Excel(InputStream in) {
init(in);
}
private void init(InputStream inputStream) throws RuntimeException {
if (inputStream == null) {
throw new NullPointerException("inputStream cannot be null");
}
try {
workbook = WorkbookFactory.create(inputStream);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public <E> E readValueAt(String cellAddress, Class<E> type) {
return readCell(cellAt(cellAddress), type);
}
public <E> List<E> readColumn(String rangeOrStartAddress, Class<E> type) {
Object[][] arr = readBlock(rangeOrStartAddress, type);
List<E> result = new LinkedList<E>();
for (int i = 0; i < arr.length; i++) {
result.add((E)arr[i][0]);
}
return result;
}
public String namedRangeToRangeAddress(String namedRange) {
int namedCellIndex = getWorkbook().getNameIndex(namedRange);
Name namedCell = getWorkbook().getNameAt(namedCellIndex);
return namedCell.getRefersToFormula();
}
public Cell cellAt(String cellAddr) {
CellReference cr = new CellReference(cellAddr);
return workbook
.getSheet(cr.getSheetName())
.getRow(cr.getRow())
.getCell((int) cr.getCol());
}
/**
* @param range either the range of the entire block to be read, or just the
* top row of the cells, in which case the method will stop when
* the first empty cell is reached in the first column
* @param columnTypes An array of data types expected at each column.
* If this array is shorter than the number of column, then the last
* data type is used until the end. So if only one value is given,
* then that is used for the entire block.
*/
public Object[][] readBlock(String range, Class... columnTypes) {
if (columnTypes == null || columnTypes.length == 0) {
throw new RuntimeException("columnTypes cannot be null / empty");
}
CellRangeAddress cra = CellRangeAddress.valueOf(range);
AreaReference ar = new AreaReference(range);
Sheet sheet = workbook.getSheet(ar.getFirstCell().getSheetName());
int firstColumn = cra.getFirstColumn();
int firstRow = cra.getFirstRow();
int lastRow = cra.getLastRow();
int height = lastRow - firstRow + 1;
int width = cra.getLastColumn() - firstColumn + 1;
List<Object> result;
if (height == 1) {
result = new LinkedList<Object>();
} else {
result = new ArrayList<Object>(height);
}
for (int rowNum = 0; moreDataToRead(sheet, firstColumn, firstRow, lastRow, rowNum); rowNum++) {
Row row = sheet.getRow(firstRow + rowNum);
Object[] resultRow = new Object[width];
result.add(resultRow);
for (int colNum = 0; colNum < width; colNum++) {
Class colType;
if (colNum < columnTypes.length - 1) {
colType = columnTypes[colNum];
} else {
colType = columnTypes[columnTypes.length - 1];
}
Cell cell = row.getCell(firstColumn + colNum);
resultRow[colNum] = readCell(cell, colType);
}
}
return result.toArray(new Object[][] {});
}
private <E> E readCell(Cell cell, Class<E> colType) {
if (colType == Date.class) {
return (E) cell.getDateCellValue();
} else if (colType == Calendar.class) {
Calendar cal = Calendar.getInstance();
cal.setTime(cell.getDateCellValue());
return (E) cal;
} else if (colType == Integer.class) {
return (E) ((Integer) ((Double) cell.getNumericCellValue()).intValue());
} else if (colType == Double.class) {
return (E) (Double) cell.getNumericCellValue();
} else if (colType == BigDecimal.class) {
return (E) new BigDecimal(String.valueOf(cell.getNumericCellValue()));
} else if (colType == String.class) {
return (E) cell.getRichStringCellValue().getString();
} else {
throw new RuntimeException("Column type not supported: " + colType);
}
}
private boolean moreDataToRead(Sheet sheet, int firstColumn, int firstRow, int lastRow, int rowNum) {
int height = lastRow - firstRow + 1;
if (height > 1 && firstRow + rowNum > lastRow) {
return false;
}
// check if the cell is empty
Row row = sheet.getRow(firstRow + rowNum);
if (row == null) {
return false;
}
Cell cell = row.getCell(firstColumn);
if (cell == null) {
return false;
}
String str = cell.toString();
return !(str == null || "".equals(str));
}
public Workbook getWorkbook() {
return workbook;
}
}