return _format.getFormatIndex();
}
+ // we keep the cached data in ThreadLocal members in order to
+ // avoid multi-threading issues when different workbooks are accessed in
+ // multiple threads at the same time
+ private static ThreadLocal<Short> lastDateFormat = new ThreadLocal<Short>() {
+ protected Short initialValue() {
+ return Short.MIN_VALUE;
+ }
+ };
+ private static ThreadLocal<List<FormatRecord>> lastFormats = new ThreadLocal<List<FormatRecord>>();
+ private static ThreadLocal<String> getDataFormatStringCache = new ThreadLocal<String>();
+
/**
* Get the contents of the format string, by looking up
* the DataFormat against the bound workbook
* @see org.apache.poi.hssf.usermodel.HSSFDataFormat
* @return the format string or "General" if not found
*/
-
- private static short lastDateFormat = Short.MIN_VALUE;
- private static List<FormatRecord> lastFormats = null;
- private static String getDataFormatStringCache = null;
-
public String getDataFormatString() {
- if (getDataFormatStringCache != null) {
- if (lastDateFormat == getDataFormat() && _workbook.getFormats().equals(lastFormats)) {
- return getDataFormatStringCache;
+ if (getDataFormatStringCache.get() != null) {
+ if (lastDateFormat.get() == getDataFormat() && _workbook.getFormats().equals(lastFormats.get())) {
+ return getDataFormatStringCache.get();
}
}
- lastFormats = _workbook.getFormats();
- lastDateFormat = getDataFormat();
+ lastFormats.set(_workbook.getFormats());
+ lastDateFormat.set(getDataFormat());
- getDataFormatStringCache = getDataFormatString(_workbook);
+ getDataFormatStringCache.set(getDataFormatString(_workbook));
- return getDataFormatStringCache;
+ return getDataFormatStringCache.get();
}
/**
// Handle matching things if we cross workbooks
if(_workbook != source._workbook) {
- lastDateFormat = Short.MIN_VALUE;
- lastFormats = null;
- getDataFormatStringCache = null;
+ lastDateFormat.set(Short.MIN_VALUE);
+ lastFormats.set(null);
+ getDataFormatStringCache.set(null);
// Then we need to clone the format string,
// and update the format record for this
import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
+import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.TempFile;
/**
assertEquals(false, r.getCell(0).getCellStyle().getShrinkToFit());
assertEquals(true, r.getCell(1).getCellStyle().getShrinkToFit());
}
+
+
+
+ private static class CellFormatBugExample extends Thread {
+ private String fileName;
+ private Throwable exception = null;
+
+ public CellFormatBugExample(String fileName) {
+ this.fileName = fileName;
+ }
+
+ @Override
+ public void run() {
+ try {
+ for(int i = 0;i< 10;i++) {
+ Workbook wb = HSSFTestDataSamples.openSampleWorkbook(fileName);
+ Sheet sheet = wb.getSheetAt(0);
+
+ for (Row row : sheet) {
+ for (Integer idxCell = 0; idxCell < row.getLastCellNum(); idxCell++) {
+
+ Cell cell = row.getCell(idxCell);
+ cell.getCellStyle().getDataFormatString();
+ if (cell.getCellType() == HSSFCell.CELL_TYPE_NUMERIC) {
+ boolean isDate = HSSFDateUtil.isCellDateFormatted(cell);
+ if (idxCell > 0 && isDate) {
+ fail("cell " + idxCell + " is not a date: " + idxCell.toString());
+ }
+ }
+ }
+ }
+ }
+ } catch (Throwable e) {
+ exception = e;
+ }
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+ };
+
+ public void test56563() throws Throwable {
+ CellFormatBugExample threadA = new CellFormatBugExample("56563a.xls");
+ threadA.start();
+ CellFormatBugExample threadB = new CellFormatBugExample("56563b.xls");
+ threadB.start();
+
+ threadA.join();
+ threadB.join();
+
+ if(threadA.getException() != null) {
+ throw threadA.getException();
+ }
+ if(threadB.getException() != null) {
+ throw threadB.getException();
+ }
+ }
}