United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-8013370 Null pointer exception when adding more than 9 accelators to a JMenuBar
JDK-8013370 : Null pointer exception when adding more than 9 accelators to a JMenuBar

Details
Type:
Bug
Submit Date:
2013-04-04
Status:
Closed
Updated Date:
2013-12-17
Project Name:
JDK
Resolved Date:
2013-06-05
Component:
client-libs
OS:
windows
Sub-Component:
javax.swing
CPU:
Priority:
P3
Resolution:
Fixed
Affected Versions:
7u9
Fixed Versions:

Related Reports
Backport:
Backport:
Backport:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version  " 1.7.0_09 " 
Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
Java HotSpot(TM) Client VM (build 23.5-b02, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
If one adds more than 10 key accelerators using the method getActionMap().put(), you will get NullPointerExceptions when the CTRL key is pressed on the keyboard.
This is caused beause the KeyboardManager::fireKeyboardAction method has changed and a null keystroke is sent to the fireBinding function.

At some point, the actions are searched using the ArrayTable::get but this class some optimization code that when you add more than ARRAY_BOUNDARY (=8), it uses a Hashtable to hold the values.

When the Java code calls the method HashTable::get(null), a NullPointerException is thrown.

REGRESSION.  Last worked in version 7

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a JFrame with a JMenu and add 10 accelerators to the menu.
Execute the application created.
Press the CTRL key.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
CTRL key should NOT throw an exception.
ACTUAL -
NullPointerException is thrown

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread  " AWT-EventQueue-0 "  java.lang.NullPointerException
at java.util.Hashtable.hash(Hashtable.java:262)
at java.util.Hashtable.get(Hashtable.java:459)
at javax.swing.ArrayTable.get(ArrayTable.java:156)
at javax.swing.InputMap.get(InputMap.java:120)
at javax.swing.JComponent.processKeyBinding(JComponent.java:2876)
at javax.swing.JMenuBar.processKeyBinding(JMenuBar.java:664)
at ui.MyMenuBar.processKeyBinding(TestJMenu.java:100)
at javax.swing.KeyboardManager.fireBinding(KeyboardManager.java:306)
at javax.swing.KeyboardManager.fireKeyboardAction(KeyboardManager.java:289)
at javax.swing.JComponent.processKeyBindingsForAllComponents(JComponent.java:2971)
at javax.swing.SwingUtilities.processKeyBindings(SwingUtilities.java:1588)
at javax.swing.UIManager$2.postProcessKeyEvent(UIManager.java:1476)
at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:772)
at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:1027)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:899)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:727)
at java.awt.Component.dispatchEventImpl(Component.java:4731)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:723)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:682)
at java.awt.EventQueue$3.run(EventQueue.java:680)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:696)
at java.awt.EventQueue$4.run(EventQueue.java:694)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:693)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package ui;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeListener;

import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.KeyStroke;

public class TestJMenu extends JFrame
{
    public TestJMenu()
    {
        MyMenuBar mb = new MyMenuBar();
        JMenu menu = new JMenu( " Menu " );
        menu.add( " Item 1 " );
        mb.add(menu);
        setJMenuBar(mb);
        setSize(400,400);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        InputMap im = mb.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        // We add exactly 10 actions because the ArrayTable is converted from a array to a hashtable when more than 8 values are added.
        for (int i=0;i<9;i++)
        {
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A+i, java.awt.event.InputEvent.CTRL_DOWN_MASK),  " theAction " +i);
            final int actId = i;
            mb.getActionMap().put( " theAction " +i, new Action(){

                @Override
                public void actionPerformed(ActionEvent e)
                {
                    JOptionPane.showMessageDialog(TestJMenu.this,  " Action executed  "  + actId);
                }

                @Override
                public Object getValue(String key)
                {
                    return null;
                }

                @Override
                public void putValue(String key, Object value)
                {
                }

                @Override
                public void setEnabled(boolean b)
                {
                }

                @Override
                public boolean isEnabled()
                {
                    return true;
                }

                @Override
                public void addPropertyChangeListener(
                    PropertyChangeListener listener)
                {
                }

                @Override
                public void removePropertyChangeListener(
                    PropertyChangeListener listener)
                {
                }});
        }
    }

    /**
     * @param args
     */
    public static void main(String[] args)
    {
        new TestJMenu().setVisible(true);
    }
}

class MyMenuBar extends JMenuBar
{
    @Override
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
        int condition, boolean pressed)
    {
        if (ks==null)
        {
            System.out.println( " Null KS is sent " );
            // Remove comment below to fix the issue.
            // return false;
        }

        return super.processKeyBinding(ks, e, condition, pressed);
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Inherit from JMenuBar and ignore the null key:

class MyMenuBar extends JMenuBar
{
    @Override
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
        int condition, boolean pressed)
    {
        if (ks==null)
        {
                return false;
        }

        return super.processKeyBinding(ks, e, condition, pressed);
    }
}

SUPPORT :
YES
                                    

Comments
Seems the problem in native code: Hashtable.cpp
                                     
2013-05-29
Seems it is regression after the 6680988 fix.
                                     
2013-05-29
http://cr.openjdk.java.net/~malenkov/8013370.8.0/
                                     
2013-06-03
URL:   http://hg.openjdk.java.net/jdk8/awt/jdk/rev/6802f71a5eb2
User:  malenkov
Date:  2013-06-05 14:16:49 +0000

                                     
2013-06-05
URL:   http://hg.openjdk.java.net/jdk8/jdk8/jdk/rev/6802f71a5eb2
User:  lana
Date:  2013-06-11 18:41:37 +0000

                                     
2013-06-11
Verified using test:
test/javax/swing/KeyboardManager/8013370/Test8013370.java

Test PASSED on Windows, Solaris, Linux, Mac under b100 .

Closed as Verified.
                                     
2013-07-29



Hardware and Software, Engineered to Work Together