Bug 54443 - ClassCastException in HSSFOptimiser
Summary: ClassCastException in HSSFOptimiser
Status: RESOLVED FIXED
Alias: None
Product: POI
Classification: Unclassified
Component: HSSF (show other bugs)
Version: 3.9-FINAL
Hardware: PC All
: P2 normal (vote)
Target Milestone: ---
Assignee: POI Developers List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-01-17 14:18 UTC by Hakan Junior
Modified: 2014-07-24 16:27 UTC (History)
0 users



Attachments
A workaround to not getting ClassCastException (3.99 KB, patch)
2013-08-14 01:52 UTC, dzareba
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Hakan Junior 2013-01-17 14:18:19 UTC
Exception in thread "main" java.lang.ClassCastException: org.apache.poi.hssf.record.StyleRecord cannot be cast to org.apache.poi.hssf.record.ExtendedFormatRecord
	at org.apache.poi.hssf.model.InternalWorkbook.getExFormatAt(InternalWorkbook.java:831)
	at org.apache.poi.hssf.usermodel.HSSFWorkbook.getCellStyleAt(HSSFWorkbook.java:1147)
	at org.apache.poi.hssf.usermodel.HSSFOptimiser.optimiseCellStyles(HSSFOptimiser.java:276)
	at com.lbs.util.WritableExcelAPI.copyCellStyle(WritableExcelAPI.java:415)
	at com.lbs.util.WritableExcelAPI.setCellFontItalicProp(WritableExcelAPI.java:591)
	at com.lbs.util.WritableExcelAPI.main(WritableExcelAPI.java:892)

Here is how i call this method;
if (workBook instanceof HSSFWorkbook&&workBook.getNumCellStyles()>3900){
   HSSFOptimiser.optimiseCellStyles((HSSFWorkbook) workBook);
....
Comment 1 Nick Burch 2013-01-17 14:39:51 UTC
Could you please upload a sample excel file that shows the problem?
Comment 2 Hakan Junior 2013-01-17 15:19:06 UTC
Hi,
The excel file is generating in memory. Here is the approach;
		for (int i = 0; i < 6; i++)
			excelAPI.setCellValue(0, i, 1, "ROW " + i);
		excelAPI.setCellFontBoldProp(0, 2, 1, true);
		excelAPI.setCellBackgroundColor(0, 2, 1, ExcelAPIConstants.COLOR_BLUE);
		excelAPI.setCellBackgroundColor(0, 0, 1, ExcelAPIConstants.COLOR_RED);

		excelAPI.groupAndOutlineRows(0, 30, 70, true);
		excelAPI.groupAndOutlineRows(0, 2, 25, true);
		//excelAPI.mergeCells(0, 0, 1, 4);

		excelAPI.setCellFontBoldProp(0, 5, 1, true);
		excelAPI.setCellFontItalicProp(0, 5, 1, true);
		
		excelAPI.setCellHyperlink(0, 0, 3, "TIKLAA",1,2,2);
		
		for (int i=0;i<15000;i++){
			excelAPI.setCellValue(1, i, 0, "Değer : "+i, i%3==0?ExcelAPIConstants.ALIGNMENT_HORIZONTAL_RIGHT:ExcelAPIConstants.ALIGNMENT_HORIZONTAL_LEFT);
			excelAPI.setCellFontBoldProp(1, i, 0, i%5==0);
			excelAPI.setCellFontItalicProp(1, i, 0, i%4==0);
			excelAPI.setCellBackgroundColor(1, i, 0, i%25==0?ExcelAPIConstants.COLOR_RED:(i%4==0?ExcelAPIConstants.COLOR_BLUE:ExcelAPIConstants.COLOR_GREEN));
		}

		excelAPI.closeExcelFile(true, false);

excelApi is a wrapper of HSSF POI APis
Comment 3 Nick Burch 2013-01-17 15:37:58 UTC
Any chance you could turn that code into a self contained junit unit test? That'd make life very easy for testing and fixing!
Comment 4 dzareba 2013-08-13 01:26:02 UTC
When there are duplicate cell styles ( i.e. via equals ), such that the later one has been used, because with HSSFOptimiser.optimiseCellStyles the way it works is that it removes the later duplicate but the earlier one wil also be removed if it has not been "used". This will effectively remove duplicated entries and mess up the records list.

I suggest to change HSSFOptimiser so slightly, as to say

isUsed[ newPos[ oldXf ] ] = true; for the part that removes unused styles, as the used one is now always the very first of all duplicates, and to not set the newPos[ duplicatedIndex ] to zero. I have tested it and no longer get an exception in such scenarios.
Comment 5 dzareba 2013-08-13 05:37:34 UTC
(In reply to dzareba from comment #4)
> When there are duplicate cell styles ( i.e. via equals ), such that the
> later one has been used, because with HSSFOptimiser.optimiseCellStyles the
> way it works is that it removes the later duplicate but the earlier one wil
> also be removed if it has not been "used". This will effectively remove
> duplicated entries and mess up the records list.
> 
> I suggest to change HSSFOptimiser so slightly, as to say
> 
> isUsed[ newPos[ oldXf ] ] = true; for the part that removes unused styles,
> as the used one is now always the very first of all duplicates, and to not
> set the newPos[ duplicatedIndex ] to zero. I have tested it and no longer
> get an exception in such scenarios.

There's another way. The thing is that duplicates should not be marked as being used. This is logical. Going through all the cells, get each and every one of their XF indexes. The XF index will always return the one which it is using, and so you want to be not using the duplicated ones, as they are going to get deleted. So mark the very first one as being used. Then what is not used has two alternatives. If it hasn't been zapped, that means it is a true unused one, else if it's already been zapped don't bother changing the positions as it already has been. Mark the new position as zero as usual for the true unused ones, as a sign of courtesy.
Comment 6 dzareba 2013-08-14 01:32:40 UTC
(In reply to dzareba from comment #4)
> When there are duplicate cell styles ( i.e. via equals ), such that the
> later one has been used, because with HSSFOptimiser.optimiseCellStyles the
> way it works is that it removes the later duplicate but the earlier one wil
> also be removed if it has not been "used". This will effectively remove
> duplicated entries and mess up the records list.
> 
> I suggest to change HSSFOptimiser so slightly, as to say
> 
> isUsed[ newPos[ oldXf ] ] = true; for the part that removes unused styles,
> as the used one is now always the very first of all duplicates, and to not
> set the newPos[ duplicatedIndex ] to zero. I have tested it and no longer
> get an exception in such scenarios.

There's another way. The thing is that duplicates should not be marked as being used. This is logical. Going through all the cells, get each and every one of their XF indexes. The XF index will always return the one which it is using, and so you want to be not using the duplicated ones, as they are going to get deleted. So mark the very first one as being used. Then what is not used has two alternatives. If it hasn't been zapped, that means it is a true unused one, else if it's already been zapped don't bother changing the positions as it already has been. Mark the new position as zero as usual for the true unused ones, as a sign of courtesy.
Comment 7 dzareba 2013-08-14 01:52:58 UTC
Created attachment 30728 [details]
A workaround to not getting ClassCastException
Comment 8 dzareba 2013-08-14 02:24:23 UTC
// simplest case this bug can be reproduced

HSSFWorkbook workbook = new HSSFWorkbook( );
HSSFCellStyle style = workbook.createCellStyle();
HSSFCellStyle newStyle = workbook.createCellStyle();
			
HSSFSheet mySheet = workbook.createSheet();
HSSFRow row = mySheet.createRow( 0 );
HSSFCell cell = row.createCell( 0 );
cell.setCellStyle( newStyle );
// style is now not assigned
			
HSSFOptimiser.optimiseCellStyles( workbook );
Comment 9 Nick Burch 2014-07-24 16:27:10 UTC
Thanks for the test case and suggested fix, should now be working as of r1613175.