2

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?

BeRecursive
  • 6,286
  • 1
  • 24
  • 41

1 Answers1

6

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);
    }
Alexander Pogrebnyak
  • 44,836
  • 10
  • 105
  • 121