Unusual Null Pointer Exception
I have a weird Null Pointer Exception being thrown. The stack trace of the exception is not specifying exactly where in my code the Null Pointer is being thrown. When this is thrown, two things are happening: 1) An item in a JComboBox has been selected, 2) A JProgressBar is given new text and is being set to Indeterminate.
The exception is not being thrown on a consistent basis, so I am at a bit of a loss. Does anyone have any ideas where I should start looking? Based on the stack trace, I almost think it is a bug in the Java Library, not my code.
Here is the stack trace:
Code :
Exception in thread "AWT-EventQueue-1" java.lang.NullPointerException
at javax.swing.plaf.basic.BasicProgressBarUI.updateSizes(BasicProgressBarUI.java:471)
at javax.swing.plaf.basic.BasicProgressBarUI.getBox(BasicProgressBarUI.java:428)
at javax.swing.plaf.metal.MetalProgressBarUI.paintIndeterminate(MetalProgressBarUI.java:139)
at javax.swing.plaf.basic.BasicProgressBarUI.paint(BasicProgressBarUI.java:393)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:143)
at javax.swing.JComponent.paintComponent(JComponent.java:752)
at javax.swing.JComponent.paint(JComponent.java:1029)
at javax.swing.JComponent.paintChildren(JComponent.java:862)
at javax.swing.JComponent.paint(JComponent.java:1038)
at javax.swing.JComponent.paintChildren(JComponent.java:862)
at javax.swing.JComponent.paint(JComponent.java:1038)
at javax.swing.JComponent.paintChildren(JComponent.java:862)
at javax.swing.JComponent.paint(JComponent.java:1038)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:567)
at javax.swing.JComponent.paintChildren(JComponent.java:862)
at javax.swing.JComponent.paint(JComponent.java:1038)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5124)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1491)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1422)
at javax.swing.RepaintManager.paint(RepaintManager.java:1225)
at javax.swing.JComponent._paintImmediately(JComponent.java:5072)
at javax.swing.JComponent.paintImmediately(JComponent.java:4882)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:786)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:714)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:694)
at javax.swing.RepaintManager.access$700(RepaintManager.java:41)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1636)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:646)
at java.awt.EventQueue.access$000(EventQueue.java:84)
at java.awt.EventQueue$1.run(EventQueue.java:607)
at java.awt.EventQueue$1.run(EventQueue.java:605)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:616)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Re: Unusual Null Pointer Exception
Quote:
Originally Posted by
aussiemcgr
The exception is not being thrown on a consistent basis, so I am at a bit of a loss. Does anyone have any ideas where I should start looking? Based on the stack trace, I almost think it is a bug in the Java Library, not my code.
I'd be very wary when stating this, as my experience has been that whenever I believe this to be true, I'm usually embarrassingly proven wrong with the bug always being due to my misunderstanding of use of Java.
Your description however is classic for that of a Swing threading error. Are you making sure to make *all* Swing calls on the event thread? Especially those calls associated with your JProgressBar? A little code might help us determine this.
Re: Unusual Null Pointer Exception
In my experience some look and feels do just this when updated from outside the EDT - erratic NullPointerExceptions when updating a UI without using SwingUtilities or using a SwingWorker. I presume you have threads going in the background given you mention JProgressBar? I presume those threads somehow make calls to the UI?
Re: Unusual Null Pointer Exception
Yeah, I'm beginning to see where the issue could be.
I do have a thread that is created when an item is selected in the JComboBox. The first thing it does is trigger the JProgressBar to indicate to the user that it is doing something, and the last thing it does is to stop the JProgressBar to indicate to the user that the operation is finished. How would I get a null pointer out of that? And is there a "safe" way of doing this that I am unaware of?
Re: Unusual Null Pointer Exception
Yes, use a SwingWorker and update the JProgressBar from the event thread only. For instance if you use a SwingWorker, you can add a PropertyChangeListener to it, and listen for the SwingWorker.StateValue to become SwingWorker.StateValue.DONE, and then stop the JProgressBar then and on the EDT.
Re: Unusual Null Pointer Exception
Quote:
How would I get a null pointer out of that?
Because some fields/variables of the BasicProgressBarUI alternate between null and not null...when updating from multiple threads one thread can set the value, try to do something with it but before it has a chance another thread can null the variables - a recipe for disaster. Use a SwingWorker or make all updates onto the EDT using SwingUtilities (invokeAndWait or invokeLater)
Re: Unusual Null Pointer Exception
For example...
Code java:
import java.awt.BorderLayout;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class SwingWorkerEg extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = 200;
public SwingWorkerEg() {
add(new JButton(new ButtonAction("Press Me")));
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("SwingWorkerEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new SwingWorkerEg());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class ButtonAction extends AbstractAction {
public ButtonAction(String title) {
super(title);
}
@Override
public void actionPerformed(ActionEvent actEvt) {
final JButton source = (JButton)actEvt.getSource();
Window win = SwingUtilities.getWindowAncestor(source);
source.setEnabled(false);
MySwingWorker mySw = new MySwingWorker();
final MyJprogressWindow myProg = new MyJprogressWindow(win);
mySw.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (SwingWorker.StateValue.DONE == pcEvt.getNewValue()) {
myProg.setVisible(false);
myProg.dispose();
source.setEnabled(true);
}
}
});
mySw.execute();
myProg.setVisible(true);
}
}
class MySwingWorker extends SwingWorker<Void, Void> {
private static final long SLEEP_TIME = 3 * 1000;
@Override
protected Void doInBackground() throws Exception {
Thread.sleep(SLEEP_TIME); // emulate long-running task
return null;
}
}
class MyJprogressWindow {
private static final String LABEL_TEXT = "Loading, ... please wait...";
private JProgressBar jprog = new JProgressBar();
private JDialog dialog;
public MyJprogressWindow(Window frame) {
jprog.setIndeterminate(true);
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(new JLabel(LABEL_TEXT, SwingConstants.CENTER), BorderLayout.NORTH);
mainPanel.add(jprog, BorderLayout.CENTER);
dialog = new JDialog(frame, "Please Wait", ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(mainPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
public void dispose() {
dialog.dispose();
}
public void setVisible(boolean visible) {
dialog.setVisible(visible);
}
}