Bug 62484

Summary: XSSFRow:OnDocumentWrite Unordered row will generate CTCells that are not referenced by _cells Treemap
Product: POI Reporter: frank
Component: XSSFAssignee: POI Developers List <dev>
Status: RESOLVED DUPLICATE    
Severity: normal    
Priority: P2    
Version: 3.17-FINAL   
Target Milestone: ---   
Hardware: All   
OS: All   

Description frank 2018-06-22 12:38:33 UTC
I have a Microsoft Excel file which has several rows that are not ordered alphabetically. Reading and writing to this Excel file will work well, until I write the XSSF-document to a file for the first time.

When I continued reading from and writing to cells in this document, I noticed some cells did not update properly in the CTRows of XSSFRows.

I debugged deeper and noticed that onDocumentWrite, for XSSFRows that are not ordered, new CTCells are created through a copy. I understand this code and it seemed logical.

<code from XSSFRow::OnDocumentWrite>
if(!isOrdered){
  cArray = new CTCell[_cells.size()];
  int i = 0;
  for (XSSFCell xssfCell : _cells.values()) {
    cArray[i] = (CTCell) xssfCell.getCTCell().copy();
              
    // we have to copy and re-create the XSSFCell here because the 
    // elements as otherwise setCArray below invalidates all the columns!
    // see Bug 56170, XMLBeans seems to always release previous objects
    // in the CArray, so we need to provide completely new ones here!
    // _cells.put(entry.getKey(), new XSSFCell(this, cArray[i]));
    // xssfCell.setCTCell(cArray[i]);
    i++;
  }
  _row.setCArray(cArray);
}

However, when this new CTCell array is set to the CTRow:
 _row.setCArray(cArray);
code in this method can (or often will) also copy these Cell objects again for its own internal row.

(The underlying classes and methods doing this are:
 XmlComplexContentImpl::arraySetterHelper( XmlObject[] sources, QName elemName)
 XmlObject::set(XmlObject src) 
  -> 
    if (monitor() == obj.monitor())             // both are in the same locale
    {
      if (noSyncThis)                         // the locale is not sync
        newObj = setterHelper( obj );
      else                                    // the locale is sync
      {
        synchronized (monitor()) {
          newObj = setterHelper( obj ); <-- new CTCell object is created
        }
      }
    }
      
)

The result is that the CTRow will now reference other CTCells than the _cells TreeMap of the XSSFRow. Writing new values to these cells will only end up in the _cells TreeMap and not in the CTRow any more. 
Consequently, writing the document a second time after having changed cell values in these rows will write the wrong cell values.

Hopefully others are also able to reproduce this issue!
Comment 1 PJ Fanning 2018-06-22 20:18:07 UTC
Marking as `normal` priority - I don't agree this a blocker.
Comment 2 PJ Fanning 2018-06-22 20:19:39 UTC
We don't encourage the use of the generated CT classes. The public APIs that we support are the XSSF ones.
Comment 3 Greg Woolsey 2018-06-27 02:05:27 UTC
This is a duplicate of bug #62130, fixed in trunk.  See that issue for the discussion and fix.

*** This bug has been marked as a duplicate of bug 62130 ***