3

I am developing a Swing application with a component performing custom painting. When I make some mistake in the painting code and an exception is thrown, the situation is hard to debug. Instead of being caught by the debugger, a popup shows with the exception information. Moreover, the thread seems to be restarted, and as the exception is a result of coding error, it is shown again and again.

When I am lucky enough to switch into the debugger (which is difficult, because more and more popups keep coming as the application gets paint requests), the debugging console shows me an exception information like:

SEVERE: Uncaught exception thrown in Thread[AWT-EventQueue-0,6,main]

.... stack follows

My application is written in Scala and I am using IntelliJ IDEA 14. My uncaught main thread exceptions are handled fine by the debugger (I have Uncaught exception enabled for Any exception breakpoint enabled in the Java Exception Breakpoints), but exceptions in AWT threads are not.

I have tried installing a handler as described in this How can I detect when an Exception's been thrown globally in Java? answer, but my handler does not seem to be triggered.

I would like to achieve following (in order of importance):

  1. avoid the AWT thread restarting on exception, or at least prevent the popup from showing
  2. handle uncaught exceptions in the debugger instead of being printed in the console

(Note: while this is Scala application, I assume the behaviour would be the same for Java, hence the Java tag).

Community
  • 1
  • 1
Suma
  • 33,181
  • 16
  • 123
  • 191
  • You mention that the exception is being thrown in paint. Are you sure? Without a stack trace it's hard to answer the question. However, if you know where the exception is coming from can you not analyse the code for errors, add exception handling. A conditional breakpoint on the line based on the exception should help. – vickirk Jan 12 '15 at 16:01

3 Answers3

8

According to this link, you have to handle both regular Exception and EDT Exception without using the old sun.awt.exception.handler hack (which does not work anymore since Java 7)

Here is your ExceptionHandler

public static class ExceptionHandler implements Thread.UncaughtExceptionHandler
{
    public void uncaughtException(Thread thread, Throwable thrown)
    {
        // TODO handle your Exception here
    }
}

Usage :

// Regular Exception
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());

// EDT Exception
SwingUtilities.invokeAndWait(new Runnable()
{
    public void run()
    {
        // We are in the event dispatching thread
        Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
    }
});
ToYonos
  • 16,469
  • 2
  • 54
  • 70
  • Great, thanks - that was what I was missing. Would you happen to know (or able to learn) why setDefaultUncaughtExceptionHandler is not enough for EDT? Does it have some kind of handler of its own? Or does setDefaultUncaughtExceptionHandler not apply to threads which are already started? The article you have linked is good, but it does not seem to explain this. – Suma Jan 09 '15 at 10:39
  • I don't know. Good question though :) – ToYonos Jan 09 '15 at 10:53
  • Accepted for now, but still waiting with the bounty award, perhaps someone will give more detail. – Suma Jan 09 '15 at 10:57
  • 2
    Your question made me push my investigation further. In fact, according to [`EventDispatchThread` source code](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/java/awt/EventDispatchThread.java#EventDispatchThread.processException%28java.lang.Throwable%29), `getDefaultUncaughtExceptionHandler` is never used in `EventDispatchThread`. On the contrary, `getUncaughtExceptionHandler()` is explicitly called in the method `processException`. That explains why `setDefaultUncaughtExceptionHandler`is not enough. – ToYonos Jan 12 '15 at 13:39
  • There is only one EDT. do we need to call Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler()); each time we use invokeAndWait() and invokeLater() ? – peterboston Dec 10 '15 at 18:07
0

In Java

Your problem is that the exception is being thrown in another thread, the event dispatch thread. A couple of solutions:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
    public void uncaughtException(Thread t, Throwable e) {
        logger.error("Uncaught exception in thread: " + t.getName, e);
    }
});

In any case you should in principle but your UI startup code in a

EventQueue.invokeLater();

or SwingUtilities.invokeLater() that directly call this.

In Scala

Your problem is that the exception is being thrown in another thread, the event dispatch thread. A couple of solutions:

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
  def uncaughtException(t: Thread, e: Throwable) {
    logger.error("Uncaught exception in thread: " + t.getName, e)
  }
})

In any case you should in principle but your UI startup code in a

EventQueue.invokeLater()
Community
  • 1
  • 1
Margus
  • 19,694
  • 14
  • 55
  • 103
  • In simple terms to answer your 2 questions, use EventQueue and if you want to see other thread exceptions set default uncaught exception handler. – Margus Jan 08 '15 at 11:03
  • As I wrote in the question, the handler installed as described in http://stackoverflow.com/questions/27603348/debug-exceptions-in-awt-queue-thread/27838458#27838458 does not trigger to me. Should it? The answer is quite old, is it still valid? – Suma Jan 08 '15 at 11:39
  • I do not understandd how is EventQueue related to my questions - how does it affect exception processing? I am talking about exceptions from paintComponent, which is already executed in EDT - what should I do with EventQueue here? – Suma Jan 08 '15 at 11:42
  • EventQueue - While the exception maybe coming from the EDT it could be that something else is accessing the resources in another thread causig the error, e.g. modifying a list, that should be executed on the EDT. Based on the available information this seems a reason attempt at answering the question, shame it was downvoted. – vickirk Jan 12 '15 at 16:05
0

Looks like your only solution might be switching to Eclipse. :-) The other solutions require coding effort and stopping in the exception handler is not the same as stopping in the exact place where the exception is thrown.

With the following program I have no problems listening to caught/uncaught instances of RuntimeException in Eclipse.

package lambda;

import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class AWTExceptionTest {
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton button = new JButton("Test");
        button.addActionListener(e -> { throw new RuntimeException(); });
        frame.add(button);
        frame.setSize(new Dimension(50, 50));
        SwingUtilities.invokeLater(() -> frame.setVisible(true));
    }
}

Here is how it looks in debug mode in Eclipse.

Eclipse in Debug mode

Jagger
  • 10,350
  • 9
  • 51
  • 93
  • 1
    I see you have your breakpoint set on RuntimeException both Caught and Uncaught. This could be done in any IDE, but it is catching too much - even exceptions which are handled well by the code. – Suma Jan 11 '15 at 00:44
  • @Suma Well I have it because I set it so. In Eclipse there is no problem to configure it so that it listens only to uncaught exceptions. – Jagger Jan 11 '15 at 09:41
  • 1
    This is the same with IntelliJ, therefore it is unlikely moving to Eclipse would help me in this respect. I am afraid if you try it, you will find EDT exceptions are not unhandled. :( – Suma Jan 12 '15 at 08:49
  • 1
    @Suma You are right. It looks like that all exceptions are caught in the EDT. I think there is a big try block in the thread that catches all the instances of `Throwable` so it does not die and therefore does not have to be restarted. I will look for another solution and update the answer accordingly if I find something. – Jagger Jan 12 '15 at 15:17
  • 1
    This agrees to what I am seeing. To my surprise, installing setUncaughtExceptionHandler as described in the answer by ToYonos works. Looking at the source code, it is because pumpOneEventForFilters calls getUncaughtExceptionHandler().uncaughtException (via processException) in the catch of the big try block you have mentioned. I can place the breakpoint in the handler, still, this is less then ideal, because the debugger will stop not when when exception is thrown, but only after the exception is catched by the EDT and passed to the handler. – Suma Jan 13 '15 at 09:44