Skip to main content

Returns values from SwingUtilities.invoke

Posted by kschaefe on November 15, 2010 at 8:47 AM PST

Last week, I updated my local copy of the SwingX source code, modifying SwingXUtilities to inlcude an invokeLater and an invokeAndWait that support return values.  I plan on checking in that code sometime today.  In one of those strange coincidences, Swing links of the week pointed me to Jan Kotek's post: SwingUtilities.invokeAndWait with return value.  It's a good article, but my solution was different.

To obtain a value, we will use a Callable (basically a Runnable that supports return values).  I use FutureTask to wrap my Callable.  A FutureTask is a Runnable, so it may be directly submitted to either of the core SwingUtilities invoke methods.  The get method in FutureTask is the method that actually returns the value (it is blocking).  So, we begin by creating a new invokeLater method to wrap SwingUtilities.invokeLater.

public static <T> FutureTask<T> invokeLater(Callable<T> callable) {
    FutureTask<T> task = new FutureTask<T>(callable);
      
    SwingUtilities.invokeLater(task);
      
    return task;
}

This method will not block the calling thread and now you have access to the FutureTask, enabling you to get the value (at some future point).  Building on that, we can create a method that blocks, just as SwingUtilities.invokeAndWait does.

public static <T> T invokeAndWait(Callable<T> callable) throws InterruptedException,
        InvocationTargetException {
    try {
        //blocks until future returns
        return invokeLater(callable).get();
    } catch (ExecutionException e) {
        Throwable t = e.getCause();
      
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else if (t instanceof InvocationTargetException) {
            throw (InvocationTargetException) t;
        } else {
            throw new InvocationTargetException(t);
        }
    }
}

By using FutureTask.get, we can create a blocking method that waits for the return value by calling get.  Since it returns wrapped exceptions, we unwrap them and pass them on as appropriate.

Related Topics >>

Comments

Great article!

Great article!

Possible Deadlock

Your invokeAndWait will deadlock, if the user accidently calls it from within the eventqueue. A simple
if (SwingUtilities.isEventDispatchThread()) throw new InvocationTargetException();
would do the trick.

Possible Deadlock

The core SwingUtilities.invokeAndWait does not check. The responsibility of not calling the method on the Event Dispatch Thread should be the callers. If anything, I think an assert would be the best option, but most people don't use them.

Returns values from

I have committed the code to Swingx, cf. Issue 1370.