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

Various containers for Action throw NPE when PropChgEvent has null newValue

XMLWordPrintable

    • b50
    • generic, x86, sparc
    • generic, linux, solaris_9, windows_nt, windows_2000, windows_xp

      Name: jk109818 Date: 01/22/2002


      FULL PRODUCT VERSION :
      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)

      Same problem occurs under 1.3.1_01.

      glibc-2.1.3-21
      Linux jesse_laptop.netbeans.com 2.2.12-20 #1 Mon Sep 27
      10:40:35 EDT 1999 i686 unknown
      Red Hat Linux release 6.1 (Cartman)


      A DESCRIPTION OF THE PROBLEM :
      Various Swing action containers, for example AbstractButton,
      JMenu, and JPopupMenu, permit a javax.swing.Action to be
      added directly as of 1.3. They listen for property changes
      on property "enabled" in order to update action state.
      However if the Action implementation fires a
      PropertyChangeEvent with a null newValue, these containers
      simply throw NPE.

      The reason is obvious in their code, e.g. JPopupMenu.java:

      } else if (propertyName.equals("enabled")) {
          Boolean enabledState = (Boolean) e.getNewValue();
          menuItem.setEnabled(enabledState.booleanValue());

      The code should check for enabledState == null and if so,
      use ((Action)e.getSource()).isEnabled() instead. It should
      also trigger the clause if propertyName == null. I imagine
      there are other such places in the code, I have only noticed
      these.

      According to the JavaBeans Specification it is acceptable to
      use a null newValue (or oldValue, or propertyName) in case
      an event source finds it too expensive to compute old and
      new values, or is not sure whether the values will actually
      be needed by someone but wishes to ensure that a change is
      fired nonetheless:

      http://java.sun.com/j2se/1.3/docs/api/java/beans/PropertyChangeEvent.html

      "Null values may be provided for the old and the new values
      if their true values are not known. An event source may send
      a null object as the name to indicate that an arbitrary set
      of if its properties have changed. In this case the old and
      new values should also be null."

      I could see no documentation overriding this proviso
      specifically for Action's, so it seems that the containers
      are at fault.

      FYI, bugs and troubles in NetBeans/Forte for Java caused by
      this:

      http://www.netbeans.org/issues/show_bug.cgi?id=13084
      http://openide.netbeans.org/servlets/ReadMsg?msgId=219999&listName=dev


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Compile and run the enclosed class. When the frame appears,
      select the menu item; an NPE is thrown. Select the toolbar
      button; ditto. Select the button and when the popup menu
      appears, select its item; ditto.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Expected results: all three uses of the action do nothing
      and throw no exception.

      Actual results: they do nothing but throw exceptions, see
      Error Messages section.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      java.lang.NullPointerException
      at
      javax.swing.JMenu$ActionChangedListener.propertyChange(JMenu.java:678)
      at
      javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:267)
      at
      javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:235)
      at
      javax.swing.AbstractAction.firePropertyChange(AbstractAction.java:181)
      at
      TestNullPropChangeNewValuesFromAction.actionPerformed(TestNullPropChangeNewValuesFromAction.java:10)
      at
      javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1770)
      at
      javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1823)
      at
      javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:422)
      at
      javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:260)
      at
      javax.swing.AbstractButton.doClick(AbstractButton.java:292)
      at
      javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1094)
      at
      javax.swing.plaf.basic.BasicMenuItemUI$MenuDragMouseHandler.menuDragMouseReleased(BasicMenuItemUI.java:993)
      at
      javax.swing.JMenuItem.fireMenuDragMouseReleased(JMenuItem.java:585)
      at
      javax.swing.JMenuItem.processMenuDragMouseEvent(JMenuItem.java:482)
      at
      javax.swing.JMenuItem.processMouseEvent(JMenuItem.java:429)
      at
      javax.swing.MenuSelectionManager.processMouseEvent(MenuSelectionManager.java:282)
      at
      javax.swing.plaf.basic.BasicMenuUI$MouseInputHandler.mouseReleased(BasicMenuUI.java:337)
      at
      java.awt.AWTEventMulticaster.mouseReleased(AWTEventMulticaster.java:230)
      at
      java.awt.Component.processMouseEvent(Component.java:5020)
      at java.awt.Component.processEvent(Component.java:4819)
      at java.awt.Container.processEvent(Container.java:1383)
      at
      java.awt.Component.dispatchEventImpl(Component.java:3527)
      at
      java.awt.Container.dispatchEventImpl(Container.java:1440)
      at java.awt.Component.dispatchEvent(Component.java:3368)
      at
      java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3219)
      at
      java.awt.LightweightDispatcher.processMouseEvent(Container.java:2930)
      at
      java.awt.LightweightDispatcher.dispatchEvent(Container.java:2866)
      at
      java.awt.Container.dispatchEventImpl(Container.java:1426)
      at java.awt.Window.dispatchEventImpl(Window.java:1568)
      at java.awt.Component.dispatchEvent(Component.java:3368)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:448)
      at
      java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:193)
      at
      java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:147)
      at
      java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:141)
      at
      java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:133)
      at
      java.awt.EventDispatchThread.run(EventDispatchThread.java:101)
      java.lang.NullPointerException
      at
      javax.swing.AbstractButton$ButtonActionPropertyChangeListener.propertyChange(AbstractButton.java:1154)
      at
      javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:267)
      at
      javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:235)
      at
      javax.swing.AbstractAction.firePropertyChange(AbstractAction.java:181)
      at
      TestNullPropChangeNewValuesFromAction.actionPerformed(TestNullPropChangeNewValuesFromAction.java:10)
      at
      javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1770)
      at
      javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1823)
      at
      javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:422)
      at
      javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:260)
      at
      javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:261)
      at
      java.awt.Component.processMouseEvent(Component.java:5020)
      at java.awt.Component.processEvent(Component.java:4819)
      at java.awt.Container.processEvent(Container.java:1383)
      at
      java.awt.Component.dispatchEventImpl(Component.java:3527)
      at
      java.awt.Container.dispatchEventImpl(Container.java:1440)
      at java.awt.Component.dispatchEvent(Component.java:3368)
      at
      java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3219)
      at
      java.awt.LightweightDispatcher.processMouseEvent(Container.java:2930)
      at
      java.awt.LightweightDispatcher.dispatchEvent(Container.java:2866)
      at
      java.awt.Container.dispatchEventImpl(Container.java:1426)
      at java.awt.Window.dispatchEventImpl(Window.java:1568)
      at java.awt.Component.dispatchEvent(Component.java:3368)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:448)
      at
      java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:193)
      at
      java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:147)
      at
      java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:141)
      at
      java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:133)
      at
      java.awt.EventDispatchThread.run(EventDispatchThread.java:101)
      java.lang.NullPointerException
      at
      javax.swing.JPopupMenu$ActionChangedListener.propertyChange(JPopupMenu.java:393)
      at
      javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:267)
      at
      javax.swing.event.SwingPropertyChangeSupport.firePropertyChange(SwingPropertyChangeSupport.java:235)
      at
      javax.swing.AbstractAction.firePropertyChange(AbstractAction.java:181)
      at
      TestNullPropChangeNewValuesFromAction.actionPerformed(TestNullPropChangeNewValuesFromAction.java:10)
      at
      javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1770)
      at
      javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1823)
      at
      javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:422)
      at
      javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:260)
      at
      javax.swing.AbstractButton.doClick(AbstractButton.java:292)
      at
      javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1094)
      at
      javax.swing.plaf.basic.BasicMenuItemUI$MouseInputHandler.mouseReleased(BasicMenuItemUI.java:934)
      at
      java.awt.Component.processMouseEvent(Component.java:5020)
      at java.awt.Component.processEvent(Component.java:4819)
      at java.awt.Container.processEvent(Container.java:1383)
      at
      java.awt.Component.dispatchEventImpl(Component.java:3527)
      at
      java.awt.Container.dispatchEventImpl(Container.java:1440)
      at java.awt.Component.dispatchEvent(Component.java:3368)
      at
      java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3219)
      at
      java.awt.LightweightDispatcher.processMouseEvent(Container.java:2930)
      at
      java.awt.LightweightDispatcher.dispatchEvent(Container.java:2866)
      at
      java.awt.Container.dispatchEventImpl(Container.java:1426)
      at java.awt.Window.dispatchEventImpl(Window.java:1568)
      at java.awt.Component.dispatchEvent(Component.java:3368)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:448)
      at
      java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:193)
      at
      java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:147)
      at
      java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:141)
      at
      java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:133)
      at
      java.awt.EventDispatchThread.run(EventDispatchThread.java:101)


      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.FlowLayout;
      import java.awt.event.ActionListener;
      import java.awt.event.ActionEvent;
      import javax.swing.*;
      public class TestNullPropChangeNewValuesFromAction extends
      AbstractAction {
          public TestNullPropChangeNewValuesFromAction() {
              super("Hi mom");
          }
          public void actionPerformed(ActionEvent e) {
              firePropertyChange("enabled", null, null);
          }
          public static void main (String args[]) {
              JFrame frame = new
      JFrame("TestNullPropChangeNewValuesFromAction");
             
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              JMenuBar menubar = new JMenuBar();
              JMenu menu = new JMenu("Test");
              menu.add(new
      TestNullPropChangeNewValuesFromAction());
              menubar.add(menu);
              frame.setJMenuBar(menubar);
              frame.getContentPane().setLayout(new FlowLayout());
              JToolBar toolbar = new JToolBar();
              toolbar.add(new
      TestNullPropChangeNewValuesFromAction());
              frame.getContentPane().add(toolbar);
              final JButton button = new JButton("Show popup");
              button.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent e) {
                      JPopupMenu popup = new JPopupMenu();
                      popup.add(new
      TestNullPropChangeNewValuesFromAction());
                      popup.show(button, 10, 10);
                  }
              });
              frame.getContentPane().add(button);
              frame.pack();
              frame.setVisible(true);
          }
      }

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

      CUSTOMER WORKAROUND :
      A work around is to always be sure to pass a newValue (and a
      property name). The disadvantage is potential loss of
      efficiency, depending on the application.
      (Review ID: 137658)
      ======================================================================

            svioletsunw Scott Violet (Inactive)
            jkimsunw Jeffrey Kim (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: