Wednesday, February 17, 2010

Beware of the SwingWorker

The SwingWorker is a nice class for executing long running tasks behind that won't block the event dispatch thread, but it has its gotchas that can be difficult to track down. The one in particular that has been the most cause of pain for me is that it swallows exceptions in the doInBackground method unless you explicitly call the get method from the done method.

Consider this seemingly simple code

SwingWorker w = new SwingWorker() {
@Override
protected Object doInBackground() throws Exception
{
throw new RuntimeException("Catch me");
}
};
w.execute();

Of course this throws an exception, right? In fact, it doesn't (well, it does but it never bubbles up so it would go completely unnoticed).

The way to ensure the exception is thrown is by calling get in the done method.


@Override
protected void done()
{
try
{
get();
}
catch (InterruptedException e)
{
throw new RuntimeException(e);
}
catch (ExecutionException e)
{
// throw the cause since the execution exception wraps the
// underlying exception
throw new RuntimeException(e.getCause());
}
}


It's an ugly solution though since the get method throws those checked exceptions but at least the exception gets thrown.

This is a very common problem when the swing worker is not returning any value and just performing a task, so you never call the get method.

1 comment: