Details
-
Bug
-
Resolution: Fixed
-
P3
-
7
-
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.
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.