How to Generate Exceptions from Repaintmanager

How to generate exceptions from RepaintManager

If it helps, the example below throws prints multiple variations of the following Exception, mostly for each phase of the frame's UI delegate initialization. I used CheckThreadViolationRepaintManager, but the AspectJ variation looks interesting, too.


java.lang.Exception
at EDTViolation$CheckThreadViolationRepaintManager.checkThreadViolations(EDTViolation.java:43)
at EDTViolation$CheckThreadViolationRepaintManager.addDirtyRegion(EDTViolation.java:37)
at javax.swing.JComponent.repaint(JComponent.java:4734)
at java.awt.Component.repaint(Component.java:3168)
at javax.swing.JComponent.setFont(JComponent.java:2727)
at javax.swing.LookAndFeel.installColorsAndFont(LookAndFeel.java:191)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(BasicPanelUI.java:49)
at javax.swing.plaf.basic.BasicPanelUI.installUI(BasicPanelUI.java:39)
at javax.swing.JComponent.setUI(JComponent.java:662)
at javax.swing.JPanel.setUI(JPanel.java:136)
at javax.swing.JPanel.updateUI(JPanel.java:109)
at javax.swing.JPanel.(JPanel.java:69)
at javax.swing.JPanel.(JPanel.java:92)
at javax.swing.JPanel.(JPanel.java:100)
at javax.swing.JRootPane.createGlassPane(JRootPane.java:528)
at javax.swing.JRootPane.(JRootPane.java:348)
at javax.swing.JFrame.createRootPane(JFrame.java:255)
at javax.swing.JFrame.frameInit(JFrame.java:236)
at javax.swing.JFrame.(JFrame.java:159)
at EDTViolation.main(EDTViolation.java:12)
...
import java.lang.ref.WeakReference;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;

/** @see https://stackoverflow.com/questions/7787998 */
public class EDTViolation {

public static void main(String args[]) {
RepaintManager.setCurrentManager(new CheckThreadViolationRepaintManager());
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.pack();
f.setVisible(true);
}

private static class CheckThreadViolationRepaintManager extends RepaintManager {
//http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html

private boolean completeCheck = true;
private WeakReference<JComponent> lastComponent;

public CheckThreadViolationRepaintManager(boolean completeCheck) {
this.completeCheck = completeCheck;
}

public CheckThreadViolationRepaintManager() {
this(true);
}

public boolean isCompleteCheck() {
return completeCheck;
}

public void setCompleteCheck(boolean completeCheck) {
this.completeCheck = completeCheck;
}

@Override
public synchronized void addInvalidComponent(JComponent component) {
checkThreadViolations(component);
super.addInvalidComponent(component);
}

@Override
public void addDirtyRegion(JComponent component, int x, int y, int w, int h) {
checkThreadViolations(component);
super.addDirtyRegion(component, x, y, w, h);
}

private void checkThreadViolations(JComponent c) {
if (!SwingUtilities.isEventDispatchThread() && (completeCheck || c.isShowing())) {
boolean repaint = false;
boolean fromSwing = false;
boolean imageUpdate = false;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement st : stackTrace) {
if (repaint && st.getClassName().startsWith("javax.swing.")
&& // for details see
// https://swinghelper.dev.java.net/issues/show_bug.cgi?id=1
!st.getClassName().startsWith("javax.swing.SwingWorker")) {
fromSwing = true;
}
if (repaint && "imageUpdate".equals(st.getMethodName())) {
imageUpdate = true;
}
if ("repaint".equals(st.getMethodName())) {
repaint = true;
fromSwing = false;
}
if ("read".equals(st.getMethodName()) && "javax.swing.JEditorPane".equals(st.getClassName())) {
// Swing reads html from a background thread
return;
}
}
if (imageUpdate) {
//assuming it is java.awt.image.ImageObserver.imageUpdate(...)
//image was asynchronously updated, that's ok
return;
}
if (repaint && !fromSwing) {
//no problems here, since repaint() is thread safe
return;
}
//ignore the last processed component
if (lastComponent != null && c == lastComponent.get()) {
return;
}
lastComponent = new WeakReference<JComponent>(c);
violationFound(c, stackTrace);
}
}

protected void violationFound(JComponent c, StackTraceElement[] stackTrace) {
System.out.println();
System.out.println("EDT violation detected");
System.out.println(c);
for (StackTraceElement st : stackTrace) {
System.out.println("\tat " + st);
}
}
}
}

How to find an exception in swing

If the error happens occasionally and it is Swing related my first guess is always a Swing threading issue, e.g. modification or access of Swing components on another thread then the EDT. This might cause an exception in the EDT, as Swing is not thread safe (more info in the Concurrency in Swing tutorial).

A good start to check for Swing threading violations is to install a custom RepaintManager, as explained in this article

I outlined more approaches in my answer on a related question.

How do I catch this exception in Swing?

As mentioned by another poster, your problem is that the exception is being thrown in another thread, the event dispatch thread. A couple of solutions:

  • put a try/catch around the actual code where the exception is occurring: e.g. if it's in response to a button click handled by an ActionListener, put the try/catch inside your actionPerformed() method;
  • or, leave the exception as an uncaught exception, and add an uncaught exception handler. For example:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
// ... do something with exception here ...
}
});

On a side-note, you should in principle but your UI startup code in a SwingUtilities.invokeLater().

how to avoid this ClassCastException?

You have an intermittent exception being thrown from a Swing GUI which highly suggests that this is a concurrency/threading issue. Are you starting the GUI on the Swing event dispatch thread? If not, please be sure to do this, especially with some Look & Feels such as Nimbus. In other words -- create your GUI within a Runnable and queue that onto the Swing event queue using SwingUtilities.invokeLater(...).

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
// create your Swing GUI and set the L&F here
});
}

If this is not the problem, then still look for other Swing threading issues, possibly using one of the approaches cited here.


Please see this bug report on the same issue. It was closed as a "non-issue" because:

This is most definitely a multithreading issue.

Again, I can now say with confidence that yours is a threading issue, that the way to solve it is to go through your code and find out where your code is violating Swing's threading rules, because most certainly it is. If you need our help, then you must show us your pertinent code, that is, code that might be violating Swing threading rules. If you won't show code, we can't give specific help.



Related Topics



Leave a reply



Submit