Search code examples
javaswingswingworkerfuture

How to catch specific thrown exception from Future?


I've recently inherited some legacy code that makes heavy use of inner classes in order to implement threads. These inner classes make the current JFrame code monolithic and so I am in the midst of re-factoring the code in order to make use of the SwingWorker class.

My SwingWorker class makes a number of API calls to a webservice and then returns the result. Since this is asynchronous this is obviously best done within the thread. Currently the way the webservice works requires a few authentication calls to validate the request. These calls can obviously return errors. What I would like to do is throw a custom exception from within the SwingWorker if these webservice calls do not authenticate. Using the standard Future pattern I have code that looks similar to the following:

SwingWorker (Background thread)

@Override
protected String doInBackground() throws Exception {
    if (!authenticationClient.authenticate(userid)) {
        throw new PlaceOrderException("Failed to authenticate client");
    }

    return orderClient.placeOrder( ... );
}

Main GUI (EDT thread)

// On the EDT
PlaceOrderWorker placeOrderWorker = new PlaceOrderWorker( ... ) {
    // This method is invoked when the worker is finished its task
    @Override
    protected void done(){
        try {
            String orderID = get();

            // Update some GUI elements using the orderID

        } catch(PlaceOrderException e) {
            JOptionPane.showMessageDialog(this, "Please review your order", e.getMessage(), JOptionPane.ERROR_MESSAGE, null);
        } catch (Exception e) {
            LOGGER.error("Error placing order", e);
        }
    }
}

The error occurs on the line:

catch(PlaceOrderException e) {
    JOptionPane.showMessageDialog(this, "Please review your order", e.getMessage(), JOptionPane.ERROR_MESSAGE, null);
} 

as Java claims this exception is never thrown.

exception PlaceOrderException is never thrown in body of corresponding try statement

Now I know that calling get will cause the exceptions to be rethrown from the thread - and it can throw a PlaceOrderException. How can I catch this specific exception? The reason I have structured my code as such is that there are a number of exceptions that can be thrown in the background thread that I want the user to be prompted about via a JDialog. The reason I am declaring the done method within the main GUI class is that I need to instantiate the JDialogs from within the EDT thread. This allows me some nice decoupling.

Anyone know of a way for me to capture this specific exception with using instanceof? Or can you suggest a better pattern to use? Perhaps SwingWorker is the wrong choice?


Solution

  • Catch ExecutionException and then investigate its cause:

        try {
            String orderID = get();
    
            // Update some GUI elements using the orderID
    
        } catch(ExecutionException e) {
            Throwable cause = e.getCause( );
            if ( cause instanceof PlaceOrderException )
            {
                JOptionPane.showMessageDialog(
                  this,
                  "Please review your order",
                  cause.getMessage(),
                  JOptionPane.ERROR_MESSAGE,
                  null
                );
            }
            else
            {
              LOGGER.error("Error placing order", e);
            }
        } catch (Exception e) {
            LOGGER.error("Error placing order", e);
        }