United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6495408 REGRESSION: JTabbedPane throws ArrayIndexOutOfBoundsException
JDK-6495408 : REGRESSION: JTabbedPane throws ArrayIndexOutOfBoundsException

Details
Type:
Bug
Submit Date:
2006-11-20
Status:
Closed
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2009-05-18
Component:
client-libs
OS:
windows_xp
Sub-Component:
javax.swing
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
5.0,5.0u9
Fixed Versions:
6u14 (b03)

Related Reports
Backport:
Duplicate:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b01)
Java HotSpot(TM) Client VM (build 1.5.0_09-b01, mixed mode)

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

A DESCRIPTION OF THE PROBLEM :
ArrayIndexOutOfBoundsException  at  javax.swing.plaf.basic.BasicTabbedPaneUI.tabForCoordinate(BasicTabbedPaneUI.java:1286) with a JTabbedPane with tab position LEFT. Seems to be a regression of bug 4962642 which is marked as fixed, reproducible always when the mouse pointer is over the position where the new tab will appear.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See bug 4962642, exception is reproducible always when the mouse pointer is over the position where the new tab will appear.

Turns out reproducing this was not as trivial as I thought, seems to involve a critical timing issue somewhere. Anyway, long story short, the code below reliably reproduces the Exception I see in my code. Key seems to be time spent generating or rendering the icon on the tab (tabs in my app have thumbnails in them).

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 1
        at javax.swing.plaf.basic.BasicTabbedPaneUI.tabForCoordinate(BasicTabbedPaneUI.java:1286)
        at javax.swing.plaf.basic.BasicTabbedPaneUI.setRolloverTab(BasicTabbedPaneUI.java:499)
        at javax.swing.plaf.basic.BasicTabbedPaneUI.access$1200(BasicTabbedPaneUI.java:37)
        at javax.swing.plaf.basic.BasicTabbedPaneUI$Handler.mouseEntered(BasicTabbedPaneUI.java:3219)
        at java.awt.Component.processMouseEvent(Component.java:5497)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3126)
        at java.awt.Component.processEvent(Component.java:5253)
        at java.awt.Container.processEvent(Container.java:1966)
        at java.awt.Component.dispatchEventImpl(Component.java:3955)
        at java.awt.Container.dispatchEventImpl(Container.java:2024)
        at java.awt.Component.dispatchEvent(Component.java:3803)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4212)
        at java.awt.LightweightDispatcher.trackMouseEnterExit(Container.java:4017)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3874)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3822)
        at java.awt.Container.dispatchEventImpl(Container.java:2010)
        at java.awt.Window.dispatchEventImpl(Window.java:1778)
        at java.awt.Component.dispatchEvent(Component.java:3803)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)


---------- BEGIN SOURCE ----------
import java.awt.*;
import javax.swing.*;
import static java.awt.RenderingHints.*;
import java.awt.event.KeyEvent;
import java.awt.geom.GeneralPath;
public class BugReport {
    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
       
        final JTabbedPane tabs = new JTabbedPane();
        tabs.setTabPlacement(JTabbedPane.LEFT);
       
        // Another (bonus) bug - if one of the tabs has html text in it
        // adding a tab with a null component will then generate an NPE
        // in Vector.elementAt(), uncomment the line below to see this
        tabs.addTab("<HTML><FONT size = 10>TAB</FONT></HTML>",new JPanel());
        tabs.addTab(null, new TabIcon(), new JPanel());
       
        JFrame frame = new JFrame("Bug Report");
        frame.setContentPane(tabs);
        frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
        frame.setBounds(100,100,200,600);
        frame.setVisible(true);
       
        Thread.sleep(1000);
       
        final Robot robot = new Robot();
        final Rectangle d = new Rectangle();
        final Point p = new Point();
       
        Runnable runner = new Runnable(){
            public void run(){
                try {
                    for (int i=0; i<7; i++){
                        Thread.sleep(1000);
                        SwingUtilities.invokeLater(new Runnable(){
                            public void run(){
                                int tab = tabs.getTabCount()-1;
                                d.setBounds(tabs.getBoundsAt(tab));
                                p.setLocation(d.x+d.width/2,d.y+d.height/2);
                                SwingUtilities.convertPointToScreen(p,tabs);
                                robot.mouseMove(p.x,p.y+d.height);
                                tabs.addTab(null, new TabIcon(), null);
                            }
                        });
                    }
                } catch (Exception ex) {}
            }
        };
        runner.run();
    }
   
    static final class TabIcon implements Icon {
        final int W = 60;
        public TabIcon() {
        }
        public int getIconHeight() {
            return W;
        }
        public int getIconWidth() {
            return W;
        }
        public void paintIcon(Component c, Graphics g, int x, int y) {
            Graphics2D g2 = (Graphics2D)g.create();
            Color iconColor = Color.BLUE;
            g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON);
            g2.setRenderingHint(KEY_RENDERING, VALUE_RENDER_QUALITY);
            g2.setColor(Color.BLUE);
            g2.fillOval(x, y, W, W);
            g2.setColor(Color.RED);
            GeneralPath path = new GeneralPath();
            path.moveTo(x+W/2,y+W/2);
            for (int i=0; i<10000; i++){
                path.lineTo(x+W/4+(float)Math.random()*W/2, y+W/4+(float)Math.random()*W/2);
            }
            g2.draw(path);
            g2.dispose();
        }
    }
}
---------- END SOURCE ----------


REPRODUCIBILITY :
This bug can be reproduced always.

                                    

Comments
EVALUATION

For the root of the problem please see evaluation for 4962642

The fix for 4962642 is incomplete, it doesn't take into account 
the case when null component is added to a JTabbedPane

see JTabbedPane.insertTab()

  if (component != null) {
            addImpl(component, null, -1);
            component.setVisible(false);
        }

if component is null we don't call addImpl and BasicTabbedPane.Handler.componentAdded()
is not called as well -> isRunsDirty is not set to true

which causes the problem
                                     
2006-11-21
WORK AROUND

add new JPanel() instead of null

tabs.addTab(null, new TabIcon(), new JPanel());
                                     
2006-11-21



Hardware and Software, Engineered to Work Together