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 JDialog
s 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?
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);
}