https://bz.apache.org/bugzilla/show_bug.cgi?id=64516

            Bug ID: 64516
           Summary: XSSFSheet.shiftRows has a bug when shifting rows
                    affect the order of the rows.
           Product: POI
           Version: 4.1.2-FINAL
          Hardware: PC
                OS: All
            Status: NEW
          Severity: normal
          Priority: P2
         Component: XSSF
          Assignee: dev@poi.apache.org
          Reporter: axel.richter.pri...@web.de
  Target Milestone: ---

Created attachment 37303
  --> https://bz.apache.org/bugzilla/attachment.cgi?id=37303&action=edit
Sample Excel file

In current Apache POI 4.1.2 XSSFSheet.shiftRows has a bug when shifting rows
affect the order of the rows. For example if one shift one row down to the end
(after the last row). So before shifting the sheet data conain:

<sheetData>
 <row r = "1"...
 <row r = "2"...
 <row r = "3"...
 <row r = "4"...
 <row r = "5"...
</sheetData>

Now we do:

XSSFSheet sheet...
...
sheet.shiftRows(2, 2, sheet.getLastRowNum() - rowNum + 1);

After that we get:

<sheetData>
 <row r = "1"...
 <row r = "2"...
 <row r = "6"...
 <row r = "4"...
 <row r = "5"...
</sheetData>

As you see, the formerly row r = "3" becaomes r = "6". But the order of sheet
data row list is not changed. That leads to a corrupt file in Excel since row
numbering and row order does not match. LibreOffice Calc is able handling that
properly.

That is because XSSFSheet.rebuildRows only rebuild the _rows map but does not
rebuild the underlying CTSheetData CTRow order.

Following complete example shows this. It also provides a rebuildRow method
which provides rebuilding the underlying CTSheetData CTRow order too.

import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;

import java.io.*;
import java.lang.reflect.*;
import java.util.*;

class XSSFShiftRowsBug {

 static void rebuildRows(XSSFSheet sheet) throws Exception {
  //rebuild the CTSheetData CTRow order
  SortedMap<Long, CTRow> ctRows = new TreeMap<Long, CTRow>();
  CTSheetData sheetData = sheet.getCTWorksheet().getSheetData();
  for (CTRow ctRow : sheetData.getRowList()) {
   Long rownumL = ctRow.getR();
   ctRows.put(rownumL, ctRow);
  }
  List<CTRow> ctRowList = new ArrayList<CTRow>(ctRows.values());
  CTRow[] ctRowArray = new CTRow[ctRowList.size()];
  ctRowArray = ctRowList.toArray(ctRowArray);
  sheetData.setRowArray(ctRowArray);

  //rebuild the _rows map
  Field rows = XSSFSheet.class.getDeclaredField("_rows");
  rows.setAccessible(true);
  @SuppressWarnings("unchecked")
  SortedMap<Integer, XSSFRow> _rows = (SortedMap<Integer,
XSSFRow>)rows.get(sheet);
  _rows.clear();
  Constructor rowConstructor =
XSSFRow.class.getDeclaredConstructor(CTRow.class, XSSFSheet.class);
  rowConstructor.setAccessible(true);
  for (CTRow ctRow : sheetData.getRowList()) {
   XSSFRow row = (XSSFRow)rowConstructor.newInstance(ctRow, sheet);
   Integer rownumI = Math.toIntExact(row.getRowNum());
   _rows.put(rownumI, row);
  }
 }

 static void shiftRowToEnd(Sheet sheet, int rowNum) throws Exception {
  if (rowNum >= sheet.getLastRowNum()) return;
  sheet.shiftRows(rowNum, rowNum, sheet.getLastRowNum() - rowNum + 1, true,
false);
  //if (sheet instanceof XSSFSheet) rebuildRows((XSSFSheet)sheet);
 }

 public static void main(String[] args) throws Exception { 

  InputStream inp = new FileInputStream("Test.xlsx"); String filePath =
"Test_1.xlsx";
  Workbook workbook = WorkbookFactory.create(inp);

  Sheet sheet = workbook.getSheetAt(0);

  shiftRowToEnd(sheet, 2);

  FileOutputStream out = new FileOutputStream(filePath);
  workbook.write(out);
  out.close();
  workbook.close();

 }
}

-- 
You are receiving this mail because:
You are the assignee for the bug.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@poi.apache.org
For additional commands, e-mail: dev-h...@poi.apache.org

Reply via email to