JDK-4623505 : ArrayIndexOutOfBoundsException due to bad update in DefaultListSelectionModel
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: windows_98
  • CPU: x86
  • Submitted: 2002-01-14
  • Updated: 2003-11-26
  • Resolved: 2003-11-26
Related Reports
Relates :  
Relates :  
Description

Name: rmT116609			Date: 01/14/2002


java version "1.4.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode)

DESCRIPTION OF THE PROBLEM :

I have made a example application which just let user remove some item from a JList.  When using SHIFT key to
make multiple selections on the JList , if you "keep pressing the SHIFT key down" during the WHOLE period of
(1)select some items at the end of the JList, (2)remove selected items, (3)select some new items at the end of the JList,
(4)remove new-selected items. Then ArrayIndexOutOfBoundsException may occur in step(4).

This is because JList's DefaultListSelectionModel has NOT been updated well, in spite that it seems so in the GUI.
In fact, this DefaultListSelectionModel's update problem also directly leads to GUI's bad event processing:
Since I clearSelection() in the actionPerformed() of step (2), although the SHIFT key is still down, the followed new
single-click on an item in JList in Step(3) should be consider as selecting the start-item (rather than the end-
item) for a multiple-selection action.  However, on the contrary, this single-click selection was considered by the
JList's GUI as selecting the end-item for a multiple- selection action.  And as shown in the above exception,
this muulti-selection contains some illegal index. I think all of these are result from the JList's
DefaultListSelectionModel' failure in updating.


The bug is reproducible on Solaris 2.8, Windows 2000, Linux Redhat 6.1 using 1.3.1_02,
1.4.0-beta3. However, on jdk1.4.0beta3 platform, the bug will be reproduced with a little 
difference.  It seems the jdk1.4beta3 has reformed the GUI for the JList class and reformed 
its event-processing for mouse-multiple-selection events.  However, this reform is NOT 
completely, in other words, NOT every mouse-multiple-selection event will be processed 
correctly.  And it seems the DefaultListSelectionModel has NOT been reformed yet.  So 
the bug I mentioned in the bugreport can still be reproduced well.  

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Start the application:
    java TestDialog

2. Select "row9", and then press SHIFT and "row8"
* ( Note: From now on, do NOT release the "SHIFT" key until step 6 in this
* experiment, even when pressing the button "Remove". )

 3. Press "Remove", then row9 and row8 are deleted correctly.

* 4. Just single-click on "row5", you will see only row5 is selected;
*    ( Thanks to the reform in jdk1.4beta3, this is the correct GUI result.
      However, as shown in step 8, this GUI reform is NOT completely. )

* 5. Press "Remvoe", the ArrayIndexOutOfBoundsException will occur.
*    ( It seems the DefaultListSelectionModel has NOT been reformed in
       jdk1.4beta3.  So the bug still exists and can be reproduced well. )

* 6. Now release the SHIFT key, just single-click on "row5";
*    ( This means I give up multiple-selection and just make a single selection
       on "row5". )

* 7. Press "Remove", you will see "row5" is deleted from both the GUI and the
     program's standard output.

* 8. Now press "SHIFT" again and then press "row2", you will see not only
     "row2", but also "row3", "row4" and "row6" are selected.
     ( That's why I said the JList's GUI reform in JDK1.4Beta3 is NOT a complete
       one.  As you saw here, the multiple selection problem still exists. )

* 9. Press "Remove", you will see "row2", "row3", "row4", "row6" are deleted
     from GUI and from the standard output.  
     ( To avoid confusion between the selection-index and the element name in
      the program's standard output, I have made a revised test-program which
     will output both the selection-index and the row-name.  The new
     test-program is attached with this email. )


EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected Result:  only row5 should be selected and deleted;

Actual Result: row5, row6, row7 are all selected and
ArrayIndexOutOfBoundsException occured when deleting.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception occurred during event dispatching:
java.lang.ArrayIndexOutOfBoundsException: 9 >= 8
        at java.util.Vector.elementAt(Vector.java:417)
        at javax.swing.DefaultListModel.remove
(DefaultListModel.java:476)
        at TestDialog.jButton1_actionPerformed
(TestDialog.java:82)
        at TestDialog$1.actionPerformed(TestDialog.java:43)
        at javax.swing.AbstractButton.fireActionPerformed
(AbstractButton.java:14
50)
        at
javax.swing.AbstractButton$ForwardActionEvents.actionPerform
ed(Abstra
ctButton.java:1504)
        at
javax.swing.DefaultButtonModel.fireActionPerformed
(DefaultButtonModel
.java:378)
        at javax.swing.DefaultButtonModel.setPressed
(DefaultButtonModel.java:250
)
        at
javax.swing.plaf.basic.BasicButtonListener.mouseReleased
(BasicButtonL
istener.java:216)
        at java.awt.Component.processMouseEvent
(Component.java:3715)
        at java.awt.Component.processEvent
(Component.java:3544)
        at java.awt.Container.processEvent
(Container.java:1164)
        at java.awt.Component.dispatchEventImpl
(Component.java:2593)
        at java.awt.Container.dispatchEventImpl
(Container.java:1213)
        at java.awt.Component.dispatchEvent
(Component.java:2497)
        at java.awt.LightweightDispatcher.retargetMouseEvent
(Container.java:2451
)
        at java.awt.LightweightDispatcher.processMouseEvent
(Container.java:2216)

        at java.awt.LightweightDispatcher.dispatchEvent
(Container.java:2125)
        at java.awt.Container.dispatchEventImpl
(Container.java:1200)
        at java.awt.Window.dispatchEventImpl
(Window.java:926)
        at java.awt.Component.dispatchEvent
(Component.java:2497)
        at java.awt.EventQueue.dispatchEvent
(EventQueue.java:339)
        at
java.awt.EventDispatchThread.pumpOneEventForHierarchy
(EventDispatchTh
read.java:131)
        at
java.awt.EventDispatchThread.pumpEventsForHierarchy
(EventDispatchThre
ad.java:98)
        at java.awt.EventDispatchThread.pumpEvents
(EventDispatchThread.java:93)
        at java.awt.EventDispatchThread.run
(EventDispatchThread.java:85)


This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;

public class TestDialog extends JDialog {
  JPanel panel1 = new JPanel();
  BorderLayout borderLayout1 = new BorderLayout();
  DefaultListModel listModel=new DefaultListModel();
  JList jList1 = new JList(listModel);
  JButton jButton1 = new JButton();

  public TestDialog(Frame frame, String title, boolean modal) {
    super(frame, title, modal);
    try {
      jbInit();
      pack();
    }
    catch(Exception ex) {
      ex.printStackTrace();
    }
  }

  public TestDialog() {
    this(null, "", false);
  }

  void jbInit() throws Exception {
    panel1.setLayout(borderLayout1);
    jButton1.setText("Remove");
    jButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jButton1_actionPerformed(e);
      }
    });
    getContentPane().add(panel1);
    panel1.add(jList1, BorderLayout.CENTER);
    panel1.add(jButton1, BorderLayout.SOUTH);

    Vector vct = new Vector();
    for (int i = 0; i < 10; i++)
      vct.addElement("row" + i);
    initListData(vct);
  }

  public void initListData(Vector data) {
    if (listModel == null) return;
    listModel.clear();

    for (int i = 0; i < data.size(); i++)
    {
      listModel.addElement(data.elementAt(i));
    }
  }

 public static void main(String args[])
 {
    TestDialog testDlg = new TestDialog(null, "Test", true);
    testDlg.setVisible(true);
    testDlg.pack();
    testDlg.dispose();
    System.exit(1);
  }

  void jButton1_actionPerformed(ActionEvent e) {
    int[] sel = jList1.getSelectedIndices();
    System.out.println("-------delete begin--------");
    for (int i = sel.length - 1; i >=0; i--)
    {
    
                System.out.println( "delete row No." + sel[i] + 
                        " : name = " + (String)listModel.get( sel[i] ) );
                listModel.remove(sel[i]);
      
    }
    
    listModel.trimToSize();
    jList1.clearSelection();
    
    System.out.println("-------delete end---------");
  }
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
There are a few ways to solve the problem:

1). Check the result of getSelectedIndices() in
actionPerformed(): check whether there is any illegal index
value before removing corresponding items from JList.

2). Make a new myDefaultListSelectionModel class which
inherit from the DefaultListSelectionModel, and override
some of its methods.
(Review ID: 137724) 
======================================================================

Comments
EVALUATION It appears to be a bug. Name: apR10133 Date: 07/30/2003 The problem is that DefaultListSelectionModel.insetrIndexIterval() incorrectly handle lead/anchor indices. So, after the selected indices are removed the anchor index is greater than total list size, hence the exception is thrown. ###@###.### ====================================================================== Name: apR10133 Date: 11/26/2003 This bug is covered by the fix for 4905083, so I'm closing it out. ###@###.### ======================================================================
24-08-2004