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

JTable.editCellAt(-1,-1) should throw IllegalArgumentException not AIOB

XMLWordPrintable

    • generic, x86, sparc
    • generic, other, solaris_2.6

      JTable.editCellAt(-1,-1) should throw IllegalArgumentException not an ArrayIndexOutOfBoundsException: -1 < 0

      Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1 < 0
      at java.lang.Throwable.fillInStackTrace(Native Method)
      at java.lang.Throwable.fillInStackTrace(Compiled Code)
      at java.lang.Throwable.<init>(Compiled Code)
      at java.lang.Exception.<init>(Compiled Code)
      at java.lang.RuntimeException.<init>(RuntimeException.java:47)
      at java.lang.IndexOutOfBoundsException.<init>(IndexOutOfBoundsException.java:44)
      at java.lang.ArrayIndexOutOfBoundsException.<init>(ArrayIndexOutOfBoundsException.java:53)
      at java.util.Vector.elementAt(Compiled Code)
      at javax.swing.table.DefaultTableColumnModel.getColumn(Compiled Code)
      at javax.swing.JTable.getCellEditor(JTable.java:2939)
      at javax.swing.JTable.editCellAt(JTable.java:2024)
      at javax.swing.JTable.editCellAt(JTable.java:1996)
      at GetEditorComponent.main(GetEditorComponent.java:109

      Testcase:
      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import javax.swing.JTable;
      import javax.swing.table.*;

      public class GetEditorComponent extends JFrame {

        static Object[][] data = {
            {"Mary", "Campione",
             "Snowboarding", new Integer(5), new Boolean(false)},
            {"Alison", "Huml",
             "Rowing", new Integer(3), new Boolean(true)},
            {"Kathy", "Walrath",
             "Chasing toddlers", new Integer(2), new Boolean(false)},
            {"Mark", "Andrews",
             "Speed reading", new Integer(20), new Boolean(true)},
            {"Angela", "Lih",
             "Teaching high school", new Integer(4), new Boolean(false)}
              };
          
          static String[] columnNames = {"First Name",
      "Last Name",
      "Sport",
      "# of Years",
      "Vegetarian"};

        static final JTable table = new JTable(data, columnNames);
        public GetEditorComponent() {
          super("Table Tests");
            
          //Create the scroll pane and add the table to it.
          JScrollPane scrollPane = new JScrollPane(table);
          
          //Add the scroll pane to this window.
          getContentPane().add(scrollPane, BorderLayout.CENTER);
          
          addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
      System.exit(0);
            }
          });
        }
        public static void main(String[] args) {
          GetEditorComponent frame = new GetEditorComponent();

          boolean tests = true;

          //System.out.println(((JTextField)table.getEditorComponent()).getText());

          if (table.getEditorComponent() != null) {
            System.out.println("Test 1: Failed!!");
            System.out.println("Expected: null , Returned: "+table.getEditorComponent());
            tests = false;
          }
          else {
            System.out.println("Test 1: Passed!!");
          }
          

          table.editCellAt(1,1);
          
          if (!(((JTextField)table.getEditorComponent()).getText().equals("Huml"))) {
            System.out.println("Test 2: Failed!!");
            System.out.println("Expected: Huml , Returned: "+((JTextField)table.getEditorComponent()).getText());
            tests = false;
          }
          else {
            System.out.println("Test 2: Passed!!");
          }
          try {
            table.editCellAt(-1,-1);
          } catch(ArrayIndexOutOfBoundsException ae) {
      System.out.println("Test 3: This test Failed to throw an IllegalArgumentException");
      ae.printStackTrace();
      tests = false;
          }
          catch(IllegalArgumentException ie) {
      System.out.println("Test 3: Passed!");
          }
          
          if(!tests)
            System.exit(1);
          else
            System.exit(0);

        }
      }


      Name: skT88420 Date: 12/20/99


      java version "1.3beta"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3beta-0)
      Java(TM) HotSpot Client VM (build 1.3beta-0, mixed mode)

      use fireTableCellUpdated frome an AbstractTableModel and pass it to int's [its?]
      this.fireTableCellUpdated(1,2);

      java.lang.ArrayIndexOutOfBoundsException: -1 < 0
         at java.util.Vector.elementAt<Vector.java:419>
         at
      javax.swing.table.DefaultTableColumnModel.getColumn<DefaultTableColumnModel.java
      :267
         at javax.swing.JTable.getCellRect<JTable.java:1780>
         at javax.swing.JTable.tabelChanged<JTable.java:2549>
         at
      javax.swing.table.AbstractTableModel.fireTableCellUpdated<AbstractTableModel.jav
      a:222>
         at
      javax.swing.table.AbstractTableModel.fireTableCellUpdated.<AbstractTableModel.ja
      va:205>
      (Review ID: 99171)
      ======================================================================
      Suggested fix provided by java.net member leouser:

      A DESCRIPTION OF THE FIX :
      BUG ID: 4291560 JTable.editCellAt(-1,-1) should throw IllegalArgumentException not AIOB
      JDK VERSION: jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
      FILES AFFECTED: javax.swing.JTable

      Discusion(embedded in test case as well):
      /**
       * BUG ID 4291560 JTable.editCellAt(-1,-1) should throw IllegalArgumentException not AIOB
       * This bug no longer exists, in fact the editCellAt method returns false
       * for these values, the issue has been resolved. But the spirit of the bug
       * is still in place. The JTable is not described as a front end to an array,
       * its a JTable! Several methods throw ArrayIndexOutOfBounds exceptions. This
       * is the wrong exception to toss to any clients if they are misbehaving. Hence
       * I have selected methods that take row,column arguments and applied tests to
       * them. The client will get an IllegalArgumentException now instead of a AIOB
       * exception. The message will be clear as to what went wrong as well. Actually
       * the test includes not just < 0 but also that the value < then its repective
       * dimensions size. It should be clear from now on what went wrong. This also
       * hides the implementation from the client as well. They should not have
       * to think in terms of the array when they get an Exception but in terms of
       * the contract.
       *
       * ANTI-RATIONALE: it will slow down some operations as the test is conducted.
       *
       * TESTING STRATEGY:
       * prove that < 0 values toss exceptions and values greater than the
       * column's and row's sizes toss exceptions. Prove legal values do
       * not toss exceptions.
       *
       * A NOTE ON WARNINGS:
       * I have eliminted 10+ warnings from the compilation of the JTable. There
       * are some like the UIDefaults being used for the Hashtable that probably
       * cannont be eliminated while that class is employed. If we switched
       * to just a Hashtable then we could probably generify it correctly and eliminate
       * the warnings.
       *
       * JDK VERSION:
       * jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
       *
       * FILE AFFECTED: javax.swing.JTable
       * test ran succesfully on a SUSE 7.3 Linux distribution
       *
       * Brian Harry
       * ###@###.###
       * Wed Jan 11, 2006
       *
       */

      UNIFIED DIFF:
      --- /home/nstuff/java6/jdk1.6.0/javax/swing/JTable.java Thu Dec 15 02:17:37 2005
      +++ /home/javarefs/javax/swing/JTable.java Wed Jan 11 12:31:09 2006
      @@ -183,6 +183,7 @@
       //
       // Static Constants
       //
      + static final long serialVersionUID = -7636743696842802177L;
       
           /**
            * @see #getUIClassID
      @@ -636,6 +637,7 @@
            */
           public JTable(final Object[][] rowData, final Object[] columnNames) {
               this(new AbstractTableModel() {
      + static final long serialVersionUID = 3489013428671730120L;
                   public String getColumnName(int column) { return columnNames[column].toString(); }
                   public int getRowCount() { return rowData.length; }
                   public int getColumnCount() { return columnNames.length; }
      @@ -1678,9 +1680,9 @@
                       if (!forDrop && state != null) {
                           clearSelection();
       
      - int[] rows = (int[])((int[][])state)[0];
      - int[] cols = (int[])((int[][])state)[1];
      - int[] anchleads = (int[])((int[][])state)[2];
      + int[] rows = ((int[][])state)[0];
      + int[] cols = ((int[][])state)[1];
      + int[] anchleads = ((int[][])state)[2];
       
                           for (int i = 0; i < rows.length; i++) {
                               addRowSelectionInterval(rows[i], rows[i]);
      @@ -2259,8 +2261,12 @@
            * @return true if <code>row</code> and <code>column</code> are valid indices
            * and the cell at index <code>(row, column)</code> is selected,
            * where the first row and first column are at index 0
      + * @throws IllegalArgumentException if the row or column is < 0.
      + * It is also thrown if the row is greater than its size
      + * or the column is greater than its size.
            */
           public boolean isCellSelected(int row, int column) {
      + checkRowColumn(row, column);
        if (!getRowSelectionAllowed() && !getColumnSelectionAllowed()) {
        return false;
        }
      @@ -2635,12 +2641,28 @@
            * @param row the row whose value is to be queried
            * @param column the column whose value is to be queried
            * @return the Object at the specified cell
      + * @throws IllegalArgumentException if the row or column is < 0.
      + * It is also thrown if the row is greater than its size
      + * or the column is greater than its size.
            */
           public Object getValueAt(int row, int column) {
      + checkRowColumn(row, column);
               return getModel().getValueAt(convertRowIndexToModel(row),
                                            convertColumnIndexToModel(column));
           }
       
      + private void checkRowColumn(int row, int column){
      + if (row < 0)
      + throw new IllegalArgumentException("row must have an index >= 0 was " + row);
      + else if(column < 0)
      + throw new IllegalArgumentException("column must have an index >= 0 was " + column);
      + else if(row >= getRowCount())
      + throw new IllegalArgumentException("row must be < getRowCount() was " + row);
      + else if(column >= getColumnCount())
      + throw new IllegalArgumentException("column must be < getColumnCount() was " + column);
      +
      + }
      +
           /**
            * Sets the value for the cell in the table model at <code>row</code>
            * and <code>column</code>.
      @@ -2658,9 +2680,13 @@
            * @param aValue the new value
            * @param row the row of the cell to be changed
            * @param column the column of the cell to be changed
      + * @throws IllegalArgumentException if the row or column is < 0.
      + * It is also thrown if the row is greater than its size
      + * or the column is greater than its size.
            * @see #getValueAt
            */
           public void setValueAt(Object aValue, int row, int column) {
      + checkRowColumn(row, column);
               getModel().setValueAt(aValue, convertRowIndexToModel(row),
                                     convertColumnIndexToModel(column));
           }
      @@ -2682,9 +2708,13 @@
            * @param row the row whose value is to be queried
            * @param column the column whose value is to be queried
            * @return true if the cell is editable
      + * @throws IllegalArgumentException if the row or column is < 0.
      + * It is also thrown if the row is greater than its size
      + * or the column is greater than its size.
            * @see #setValueAt
            */
           public boolean isCellEditable(int row, int column) {
      + checkRowColumn(row, column);
               return getModel().isCellEditable(convertRowIndexToModel(row),
                                                convertColumnIndexToModel(column));
           }
      @@ -5328,6 +5358,7 @@
            * Default Renderers
            **/
           static class NumberRenderer extends DefaultTableCellRenderer.UIResource {
      + static final long serialVersionUID = 1060206325840761774L;
        public NumberRenderer() {
        super();
        setHorizontalAlignment(JLabel.RIGHT);
      @@ -5335,6 +5366,7 @@
           }
       
           static class DoubleRenderer extends NumberRenderer {
      + static final long serialVersionUID = 1674361569623087628L;
        NumberFormat formatter;
        public DoubleRenderer() { super(); }
       
      @@ -5347,6 +5379,7 @@
           }
       
           static class DateRenderer extends DefaultTableCellRenderer.UIResource {
      + static final long serialVersionUID = 1127156928504609172L;
        DateFormat formatter;
        public DateRenderer() { super(); }
       
      @@ -5359,6 +5392,7 @@
           }
       
           static class IconRenderer extends DefaultTableCellRenderer.UIResource {
      + static final long serialVersionUID = 1827488161207459271L;
        public IconRenderer() {
        super();
        setHorizontalAlignment(JLabel.CENTER);
      @@ -5369,6 +5403,7 @@
       
           static class BooleanRenderer extends JCheckBox implements TableCellRenderer, UIResource
           {
      + static final long serialVersionUID = -6514652581882111685L;
               private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
       
        public BooleanRenderer() {
      @@ -5424,7 +5459,7 @@
            * Default Editors
            */
           static class GenericEditor extends DefaultCellEditor {
      -
      + static final long serialVersionUID = 1610870512073123683L;
        Class[] argTypes = new Class[]{String.class};
        java.lang.reflect.Constructor constructor;
        Object value;
      @@ -5487,13 +5522,14 @@
           }
       
           static class NumberEditor extends GenericEditor {
      -
      + static final long serialVersionUID = -1513302533261375866L;
        public NumberEditor() {
        ((JTextField)getComponent()).setHorizontalAlignment(JTextField.RIGHT);
        }
           }
       
           static class BooleanEditor extends DefaultCellEditor {
      + static final long serialVersionUID = 9146800834153813719L;
        public BooleanEditor() {
        super(new JCheckBox());
        JCheckBox checkBox = (JCheckBox)getComponent();
      @@ -5650,11 +5686,15 @@
            * @return the assigned renderer; if <code>null</code>
            * returns the default renderer
            * for this type of object
      + * @throws IllegalArgumentException if the row or column is < 0.
      + * It is also thrown if the row is greater than its size
      + * or the column is greater than its size.
            * @see javax.swing.table.DefaultTableCellRenderer
            * @see javax.swing.table.TableColumn#setCellRenderer
            * @see #setDefaultRenderer
            */
           public TableCellRenderer getCellRenderer(int row, int column) {
      + checkRowColumn(row, column);
               TableColumn tableColumn = getColumnModel().getColumn(column);
               TableCellRenderer renderer = tableColumn.getCellRenderer();
               if (renderer == null) {
      @@ -5731,9 +5771,13 @@
            * @return the editor for this cell;
            * if <code>null</code> return the default editor for
            * this type of cell
      + * @throws IllegalArgumentException if the row or column is < 0.
      + * It is also thrown if the row is greater than its size
      + * or the column is greater than its size.
            * @see DefaultCellEditor
            */
           public TableCellEditor getCellEditor(int row, int column) {
      + checkRowColumn(row, column);
               TableColumn tableColumn = getColumnModel().getColumn(column);
               TableCellEditor editor = tableColumn.getCellEditor();
               if (editor == null) {
      @@ -5766,7 +5810,8 @@
                                                         row, column);
               if (comp instanceof JComponent) {
        JComponent jComp = (JComponent)comp;
      - if (jComp.getNextFocusableComponent() == null) {
      + FocusTraversalPolicy ftp = getFocusTraversalPolicy();
      + if ( ftp.getComponentAfter(getParent(), this) == null) {
        jComp.setNextFocusableComponent(this);
        }
        }
      @@ -6560,6 +6605,7 @@
           implements AccessibleSelection, ListSelectionListener, TableModelListener,
           TableColumnModelListener, CellEditorListener, PropertyChangeListener,
           AccessibleExtendedTable {
      + static final long serialVersionUID = -1960919093900809477L;
       
               int lastSelectedRow;
               int lastSelectedCol;
      @@ -8623,7 +8669,7 @@
                       } else {
                           Component c = getCurrentComponent();
                           if (c != null) {
      - return c.isFocusTraversable();
      + return c.isFocusable();
                           } else {
                               return false;
                           }
      @@ -9475,7 +9521,7 @@
                       } else {
                           Component c = getCurrentComponent();
                           if (c != null) {
      - return c.isFocusTraversable();
      + return c.isFocusable();
                           } else {
                               return false;
                           }


      JUnit TESTCASE :
      import junit.framework.TestCase;
      import junit.textui.TestRunner;
      import static java.lang.System.out;
      import java.util.Vector;
      import javax.swing.*;
      import javax.swing.table.*;

      /**
       * BUG ID 4291560 JTable.editCellAt(-1,-1) should throw IllegalArgumentException not AIOB
       * This bug no longer exists, in fact the editCellAt method returns false
       * for these values, the issue has been resolved. But the spirit of the bug
       * is still in place. The JTable is not described as a front end to an array,
       * its a JTable! Several methods throw ArrayIndexOutOfBounds exceptions. This
       * is the wrong exception to toss to any clients if they are misbehaving. Hence
       * I have selected methods that take row,column arguments and applied tests to
       * them. The client will get an IllegalArgumentException now instead of a AIOB
       * exception. The message will be clear as to what went wrong as well. Actually
       * the test includes not just < 0 but also that the value < then its repective
       * dimensions size. It should be clear from now on what went wrong. This also
       * hides the implementation from the client as well. They should not have
       * to think in terms of the array when they get an Exception but in terms of
       * the contract.
       *
       * ANTI-RATIONALE: it will slow down some operations as the test is conducted.
       *
       * TESTING STRATEGY:
       * prove that < 0 values toss exceptions and values greater than the
       * column's and row's sizes toss exceptions. Prove legal values do
       * not toss exceptions.
       *
       * A NOTE ON WARNINGS:
       * I have eliminted 10+ warnings from the compilation of the JTable. There
       * are some like the UIDefaults being used for the Hashtable that probably
       * cannont be eliminated while that class is employed. If we switched
       * to just a Hashtable then we could probably generify it correctly and eliminate
       * the warnings.
       *
       * JDK VERSION:
       * jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
       *
       * FILE AFFECTED: javax.swing.JTable
       * test ran succesfully on a SUSE 7.3 Linux distribution
       *
       * Brian Harry
       * ###@###.###
       * Wed Jan 11, 2006
       *
       */
      public class TestTable extends TestCase{

          public TestTable(String method){
      super(method);
          }

          public void testTable(){
      out.println();
      out.println("Testing Illegal indices for JTable...");
      Vector<Vector<Integer>> v = new Vector<Vector<Integer>>();
      for(int i = 0; i < 10; i++){
      Vector<Integer> v2 = new Vector<Integer>();
      for(int j = 0; j < 10; j++)
      v2.add(j);
      v.add(v2);

      }
      Vector<String> names = new Vector<String>();
      for(int i = 0; i < 10; i ++)
      names.add(String.valueOf(i));
      DefaultTableModel dtm = new DefaultTableModel(v,names );
      JTable jt = new JTable(dtm);
      try{
      jt.setValueAt(100,-1,-1);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for -1, -1 setValueAt as planned");
      }
      try{
      jt.setValueAt(100,20,20);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for 20, 20 setValueAt as planned");
      }
      try{
      jt.isCellEditable(1,-1);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for 1, -1 isCellEditable as planned");
      }
      try{
      jt.isCellEditable(20,20);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for 20, 20 isCellEditable as planned");
      }
      try{
      jt.getCellRenderer(-1,-1);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for -1, -1 getCellRenderer as planned");
      }
      try{
      jt.getCellRenderer(20,20);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for 20, 20 getCellRenderer as planned");
      }
      try{
      jt.getCellEditor(-1,-1);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for -1, -1 getCellEditor as planned");
      }
      try{
      jt.getCellEditor(20,20);
      }
      catch(IllegalArgumentException x){
      out.println( "Thrown IllegalArgumentException for 20, 20 getCellEditor as planned");
      }
      try{
      jt.getValueAt(-1,-1);
      }
       [too long to put here...truncated...]
      refer to attached file 623943.txt for the rest

            serb Sergey Bylokhov
            collins Gary Collins (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: