I wrote the following convenience method to add to jtahlborn's answer. It adds a check to avoid blocking the EDT, and provides a nice stream-lined exception handling:
/**
* executes the given callable on the EDT, blocking and returning the result of the callable.call() method.
*
* If call() throws an exception, it is rethrown on the the current thread if the exception is either a RuntimeException, or the
* class that is assignable to exceptionClass. Otherwise, it is wrapped in a RuntimeException and thrown on the current thread.
*
* @param exceptionClass The class of any exception that may be thrown by the callable.call() method, which will now be thrown
* directly by this method (ie, not wrapped in an ExecutionException)
*/
public static <T, E extends Exception> T invokeAndWaitAndReturn(Callable<T> callable, Class<E> exceptionClass)
throws InterruptedException, E {
if (SwingUtilities.isEventDispatchThread()) {
try {
return callable.call();
}
catch (Exception e) {
throw throwException(exceptionClass, e);
}
}
else {
FutureTask<T> task = new FutureTask<T>(callable);
SwingUtilities.invokeLater(task);
try {
return task.get();
}
catch (ExecutionException ee) {
throw throwException(exceptionClass, ee.getCause());
}
}
}
@SuppressWarnings("unchecked")
private static <E extends Exception> E throwException(Class<E> exceptionClass, Throwable t) {
if (exceptionClass.isAssignableFrom(t.getClass())) {
return (E) t;
}
else if (t instanceof RuntimeException) {
throw (RuntimeException) t;
}
else {
throw new RuntimeException(t);
}
}
You call it like this, and don't need to worry whether you are currently executing on the EDT or not:
try {
Integer result = invokeAndWaitAndReturn(new Callable<Integer>() {
public Integer call() throws MyException {
// do EDT stuff here to produce the result
}
}, MyException.class);
} catch(InterruptedException ie) {
Thread.currentThread().interrupt();
} catch(MyException me) {
// handle the "expected" Exception here
}