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

NPE when using SynthTreeUI's expandPath()

    XMLWordPrintable

Details

    • b102
    • linux

    Description

      FULL PRODUCT VERSION :
      java version " 1.7.0_19 "
      OpenJDK Runtime Environment (fedora-2.3.9.3.fc18-x86_64)
      OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Linux fritocomp 3.8.11-200.fc18.x86_64 #1 SMP Wed May 1 19:44:27 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

      EXTRA RELEVANT SYSTEM CONFIGURATION :
      $ rpm -qa | grep openjdk
      java-1.7.0-openjdk-javadoc-1.7.0.19-2.3.9.3.fc18.noarch
      java-1.7.0-openjdk-devel-1.7.0.19-2.3.9.3.fc18.x86_64
      java-1.7.0-openjdk-1.7.0.19-2.3.9.3.fc18.x86_64

      A DESCRIPTION OF THE PROBLEM :
      When using the GTK " Synth " look and feel, a NullPointerException occurs within SynthTreeUI. This seems to occur whenever a path is expanded that is no longer in a tree. Nimbus, Metal, and other look and feels do not throw an NPE under this condition.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      The attached test case is probably the best place to see reproduction steps, but here's a summary:

      1. Ensure the GTK look and feel is enabled
      2. Create a JTree that uses the DefaultTreeModel
      3. Add a TreeModelListener that expands paths when a node is inserted
      4. Insert a node into the root node using insertNodeInto
      5. Immediately remove the inserted node using removeNodeFrom

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      An empty tree is shown.
      ACTUAL -
      A NullPointerException is thrown.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Exception in thread " AWT-EventQueue-0 " java.lang.NullPointerException
      at javax.swing.plaf.synth.SynthTreeUI.paint(SynthTreeUI.java:357)
      at javax.swing.plaf.synth.SynthTreeUI.update(SynthTreeUI.java:271)
      at javax.swing.JComponent.paintComponent(JComponent.java:769)
      at javax.swing.JComponent.paint(JComponent.java:1045)
      at javax.swing.JComponent.paintChildren(JComponent.java:878)
      at javax.swing.JComponent.paint(JComponent.java:1054)
      at javax.swing.JComponent.paintChildren(JComponent.java:878)
      at javax.swing.JComponent.paint(JComponent.java:1054)
      at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
      at javax.swing.JComponent.paintChildren(JComponent.java:878)
      at javax.swing.JComponent.paintToOffscreen(JComponent.java:5219)
      at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:295)
      at javax.swing.RepaintManager.paint(RepaintManager.java:1236)
      at javax.swing.JComponent.paint(JComponent.java:1031)
      at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
      at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:78)
      at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:115)
      at java.awt.Container.paint(Container.java:1967)
      at java.awt.Window.paint(Window.java:3877)
      at javax.swing.RepaintManager$3.run(RepaintManager.java:807)
      at javax.swing.RepaintManager$3.run(RepaintManager.java:784)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
      at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:784)
      at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:757)
      at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:706)
      at javax.swing.RepaintManager.access$1000(RepaintManager.java:62)
      at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1651)
      at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
      at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:727)
      at java.awt.EventQueue.access$200(EventQueue.java:103)
      at java.awt.EventQueue$3.run(EventQueue.java:688)
      at java.awt.EventQueue$3.run(EventQueue.java:686)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:697)
      at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
      at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
      at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
      at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import javax.swing.JFrame;
      import javax.swing.JTree;
      import javax.swing.SwingUtilities;
      import javax.swing.UIManager;
      import javax.swing.UIManager.LookAndFeelInfo;
      import javax.swing.event.TreeModelEvent;
      import javax.swing.event.TreeModelListener;
      import javax.swing.tree.DefaultMutableTreeNode;
      import javax.swing.tree.DefaultTreeModel;

      public class SynthTreeUIBugs extends JFrame {

      private final JTree tree = new JTree();
      private final DefaultMutableTreeNode root = new DefaultMutableTreeNode();
      private final DefaultTreeModel model = new DefaultTreeModel(root);

      public SynthTreeUIBugs() {
      super( " SynthTreeUIBugs " );

      getContentPane().add(tree);
      tree.setModel(model);

      model.addTreeModelListener(new TreeModelListener() {

      @Override
      public void treeStructureChanged(TreeModelEvent event) {
      // Do nothing
      }

      @Override
      public void treeNodesRemoved(TreeModelEvent event) {
      // Do nothing
      }

      @Override
      public void treeNodesInserted(final TreeModelEvent event) {
      tree.expandPath(event.getTreePath());
      }

      @Override
      public void treeNodesChanged(TreeModelEvent event) {
      // Do nothing
      }
      });

      DefaultMutableTreeNode child = new DefaultMutableTreeNode( " Child " );
      model.insertNodeInto(child, root, root.getChildCount());
      model.removeNodeFromParent(child);
      }

      public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
      activateGTKLookAndFeel();
      JFrame frame = new SynthTreeUIBugs();
      frame.setSize(500, 500);
      frame.setLocationRelativeTo(null);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setVisible(true);
      }
      });
      }

      public static void activateGTKLookAndFeel() {
      for (final LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
      if (info.getName().contains( " GTK " )) {
      try {
      UIManager.setLookAndFeel(info.getClassName());
      } catch (final Exception e) {
      System.err.println(e);
      }
      }
      }
      }

      private static final long serialVersionUID = 1L;
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Easiest workaround is to defer the expandPath() code using SwingUtilities.invokeLater.

      A more coarse-grained workaround is to not use the GTK look and feel.

      Attachments

        Activity

          People

            malenkov Sergey Malenkov (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: