Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-7007967

DefaultRowSorter: incorrect sorting due to not updating comparator cache

    XMLWordPrintable

    Details

    • Subcomponent:
    • Resolved In Build:
      b01
    • CPU:
      generic
    • OS:
      generic

      Description

      the issue was reported on the OTN swing forum

      http://forums.oracle.com/forums/thread.jspa?threadID=2146814&tstart=0

      Some details of my track down is there as well, below a failing unit test. The basic problem is the comparator flag caching in the boolean array field useToString, it's not updated in the "optimized" rowsInserted0/rowsDeleted0

      - on block delete, the "normal" sort triggered in shouldUseOptimized updates the per-column comparator flags are updated. At that point the empty model returns Object.class which results in a true for useToString
      - subsequent single line inserts pass through the rowsInserted0 which doesn't update the flags (though the content now is an integer and the comparator available) thus still using the string comparison

      My suggestion is to remove the useToString array completely - aliasing foreign state is always error prone and here doesn't buy much. Instead, replace by a method useToString(column) which is called whenever needed (which is solely in compare(...))

      This is a major glitch, IMO, as it results in incorrect sorting which is highly visible to end users plus there is no way to work around in custom rowSorters because everything is private.

      /*
       * Created on 19.12.2010
       *
       */
      package org.jdesktop.swingx.sort;

      import javax.swing.table.DefaultTableModel;
      import javax.swing.table.TableRowSorter;

      import junit.framework.TestCase;

      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.junit.runners.JUnit4;

      /**
       * DefaultRowSorter with incorrect sorting with models that return columnClass
       * based on actual content.
       *
       * The test case simulates the steps to reproduce
       * - initialize such a model with ascending Integers.
       * - initialize a TableRowSorter with the model and toggle sort to ascending
       * - sanity assert original (natural integer) ascending order of values
       * - block delete all data in the model and notify the sorter
       * - re-fill with model with initial data and notify sorter (line by line)
       * - assert native integer ascending order fails (because the data is sorted by string)
       *
       * @author Jeanette Winzenburg, Berlin
       */
      @RunWith(JUnit4.class)
      public class DefaultRowSorterCachUseStringComparatorBug extends TestCase {

          @Test
          public void testSortOptimized() {
              Object[] values = new Object[] { 1, 2, 10} ;
              Object[][] data = new Object[][] {
                      { values[0]},
                      { values[1]},
                      { values[2]}
                      };

              DefaultTableModel model = new DefaultTableModel(data, new Object[] {"A"}) {

                  /**
                   * @inherited <p>
                   */
                  @Override
                  public Class<?> getColumnClass(int columnIndex) {
                      if (getRowCount() >0) {
                          return getValueAt(0, columnIndex).getClass();
                      }
                      return super.getColumnClass(columnIndex);
                  }

              };

              TableRowSorter<DefaultTableModel> rowSorter = new TableRowSorter<DefaultTableModel>(model);
              rowSorter.toggleSortOrder(0);
              for (int row = 0; row < model.getRowCount(); row++) {
                  // values are naturally sorted ascending
                  // - so with ascending sorting the coordinate transformation is identidy
                  assertEquals("sanity: identity initially", row, rowSorter.convertRowIndexToView(row));
              }
              // clear model and notify sorter
              model.setRowCount(0);
              rowSorter.rowsDeleted(0, values.length - 1);
              // refill the model and notify sorter
              for (int i = 0; i < values.length; i++) {
                  model.addRow(new Object[] { values[i]});
                  rowSorter.rowsInserted(i, i);
              }
              for (int row = 0; row < model.getRowCount(); row++) {
                  // values are naturally sorted ascending
                  // - so with ascending sorting the coordinate transformation is identidy
                  assertEquals("identity after refill", row, rowSorter.convertRowIndexToView(row));
              }
          }
      }

        Attachments

          Activity

            People

            Assignee:
            pbansal Pankaj Bansal
            Reporter:
            alexp Alexander Potochkin (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: