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

~1ms updates to JTable (w/ TableRowSorter)’s model throws NullPointerException

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P3 P3
    • None
    • 6
    • client-libs

      FULL PRODUCT VERSION :
      java version "1.6.0_01"
      Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
      Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      A DESCRIPTION OF THE PROBLEM :
      Adding rows to a javax.swing.JTable 's model with a javax.swing.table.TableRowSorter at a very high rate (~1ms per add) sporadically causes a java.lang.NullPointerException to be thrown. By sporadically, I mean a number of times in a run with 100 rows being added, but not always at the same row being added.

      Removing the TableRowSorter eliminates the problem.

      The problem also does not happen (with the TableRowSorter in place) if the rate of adding is slowed down (increasing DELAY_BETWEEN_ADDS_MS).

      Note: Unable to reproduce the issue on Linux (Linux zippy 2.6.20-16-generic #2 SMP Thu Jun 7 20:19:32 UTC 2007 i686 GNU/Linux)


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the supplied code on a Windows XP machine.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Ability to add rows to a sorted table at a very high rate without exceptions being thrown.
      ACTUAL -
      Sporadic NullPointerException are thrown.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
              at javax.swing.DefaultRowSorter.convertRowIndexToModel(Unknown Source)
              at javax.swing.JTable.convertRowIndexToModel(Unknown Source)
              at javax.swing.JTable.getValueAt(Unknown Source)
              at javax.swing.JTable.prepareRenderer(Unknown Source)
              at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
              at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
              at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
              at javax.swing.plaf.ComponentUI.update(Unknown Source)
              at javax.swing.JComponent.paintComponent(Unknown Source)
              at javax.swing.JComponent.paint(Unknown Source)
              at javax.swing.JComponent.paintChildren(Unknown Source)
              at javax.swing.JComponent.paint(Unknown Source)
              at javax.swing.JViewport.paint(Unknown Source)
              at javax.swing.JComponent.paintChildren(Unknown Source)
              at javax.swing.JComponent.paint(Unknown Source)
              at javax.swing.JComponent.paintToOffscreen(Unknown Source)
              at javax.swing.BufferStrategyPaintManager.paint(Unknown Source)
              at javax.swing.RepaintManager.paint(Unknown Source)
              at javax.swing.JComponent._paintImmediately(Unknown Source)
              at javax.swing.JComponent.paintImmediately(Unknown Source)
              at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
              at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
              at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
              at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
              at java.awt.event.InvocationEvent.dispatch(Unknown Source)
              at java.awt.EventQueue.dispatchEvent(Unknown Source)
              at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
              at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
              at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
              at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
              at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
              at java.awt.EventDispatchThread.run(Unknown Source)

      REPRODUCIBILITY :
      This bug can be reproduced occasionally.

      ---------- BEGIN SOURCE ----------
      import javax.swing.JFrame;
      import javax.swing.JTable;
      import javax.swing.table.AbstractTableModel;
      import javax.swing.table.TableRowSorter;
      import javax.swing.JScrollPane;
      import java.util.concurrent.ConcurrentHashMap;
      import java.lang.Thread;
      import java.lang.InterruptedException;

      public class ProblemJTable {

         public class Data {
            private int intValue;
            private String stringVal;
            private double doubleVal;
            private long dateTimeVal;

            public Data(int intValue, String stringVal, double doubleVal,
                  long dateTimeVal) {
               super();
               this.intValue = intValue;
               this.stringVal = stringVal;
               this.doubleVal = doubleVal;
               this.dateTimeVal = dateTimeVal;
            }

            public int getIntValue() {
               return intValue;
            }

            public String getStringVal() {
               return stringVal;
            }

            public double getDoubleVal() {
               return doubleVal;
            }

            public long getDateTimeVal() {
               return dateTimeVal;
            }

         }

         private enum Columns {
            INTEGER("Integer", Integer.class),

            STRING("String", String.class),

            DOUBLE("Double", Double.class),

            DATE("Date", Long.class),

            TIME("Trans Time", Long.class);

            private String name;
            private Class<?> classType;

            private final static Columns elements[] = values();

            public final static int length = values().length;

            Columns(final String name, final Class<?> classType) {
               this.name = name;
               this.classType = classType;
            }

            public static final Columns get(final int i) {
               return elements[i];
            }

            public final String getName() {
               return name;
            }

            public final Class<?> getClassType() {
               return classType;
            }
         }

         private class TableModel extends AbstractTableModel {

            private final ConcurrentHashMap<Integer, Data> dataByRowMap = new ConcurrentHashMap<Integer, Data>();
            private final ConcurrentHashMap<Data, Integer> rowByDataMap = new ConcurrentHashMap<Data, Integer>();

            public synchronized int getRowCount() {
               return rowByDataMap.size();
            }

            public int getColumnCount() {
               return Columns.length;
            }

            public String getColumnName(int columnIndex) {
               return Columns.get(columnIndex).getName();
            }

            public Class<?> getColumnClass(int columnIndex) {
               return Columns.get(columnIndex).getClassType();
            }

            public synchronized Object getValueAt(int rowIndex, int columnIndex) {
               Object rtnValue = null;
               Integer row = rowIndex;
               Columns col = Columns.get(columnIndex);
               Data data = null;

               data = dataByRowMap.get(row);
               if (null != data) {

                  switch (col) {
                  case INTEGER:
                     rtnValue = data.getIntValue();
                     break;

                  case STRING:
                     rtnValue = data.getStringVal();
                     break;

                  case DOUBLE:
                     rtnValue = data.getDoubleVal();
                     break;

                  case DATE:
                  case TIME:
                     rtnValue = data.getDateTimeVal();
                     break;
                  }
               }

               return rtnValue;
            }

            public synchronized void add(Data data) {
               Integer row;
               row = rowByDataMap.get(data);
               if (null == row) {
                  row = rowByDataMap.size();
                  rowByDataMap.put(data, row);
                  dataByRowMap.put(row, data);
                  fireTableRowsInserted(row, row);
               } else {
                  fireTableRowsUpdated(row, row);
               }
            }
         }

         private JFrame frame;
         private JScrollPane scrollPane;
         private JTable table;
         private static final int NUMBER_OF_ADDS = 100;
         final static long DELAY_BETWEEN_ADDS_MS = 1;

         public static void main(String[] args) {

            ProblemJTable problemJTable = null;
            Data data = null;

            try {
               problemJTable = new ProblemJTable();
            } catch (java.lang.Exception e) {
               e.printStackTrace();
            }

            // Delay adding rows for a bit.
            try {
               Thread.sleep(500);
            } catch (InterruptedException e) {
               e.printStackTrace();
            }
            
            // Add rows.
            for (int i = 0; i < NUMBER_OF_ADDS; i++) {
               data = problemJTable.new Data(i, "Str", i * 1.0, i * 1L);
               ((TableModel) problemJTable.table.getModel()).add(data);
               try {
                  Thread.sleep(DELAY_BETWEEN_ADDS_MS);
               } catch (InterruptedException e) {
                  e.printStackTrace();
               }
            }
         }

         public ProblemJTable() {
            initialize();
         }

         private void initialize() {

            frame = new JFrame();
            frame.getContentPane().setLayout(null);
            frame.setBounds(100, 100, 300, 300);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            scrollPane = new JScrollPane();
            scrollPane.setBounds(0, 0, 275, 275);
            frame.getContentPane().add(scrollPane);

            table = new JTable();
            table.setModel(new TableModel());

            // --------------------------------------------------------------------
            // --------------------------------------------------------------------
            // *** COMMENT OUT CODE BELOW FOR NO EXCEPTIONS
            // Set up sorting.
            table.setRowSorter(new TableRowSorter<TableModel>((TableModel) table
                  .getModel()));
            table.getRowSorter().toggleSortOrder(0);
            table.getRowSorter().toggleSortOrder(0);
            // *** COMMENT OUT CODE ABOVE FOR NO EXCEPTIONS
            // --------------------------------------------------------------------
            // --------------------------------------------------------------------

            scrollPane.setViewportView(table);

            frame.setVisible(true);
         }

      }

      ---------- END SOURCE ----------

            Unassigned Unassigned
            igor Igor Nekrestyanov (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: