Search code examples
javagwtexceptiontomcat8http-error

GWT - Unable to catch StatusCodeException with UncaughtExceptionHandler


When Tomcat session times out, I want to redirect my user to the homepage of my GWT app, so that they can login again. To force this, I'm trying to use the StatusCodeException thrown by GWT when the user tries to perform any operation after their session times out -

SEVERE: com.google.gwt.user.client.rpc.StatusCodeException: 0  

To achieve this, I'm using the following code -

public void onModuleLoad() {
    GWT.UncaughtExceptionHandler uncaughtExceptionHandler = new GWT.UncaughtExceptionHandler() {
        public void onUncaughtException(Throwable e) {
            if (e instanceof StatusCodeException) {
                logger.log(Level.ERROR, "Exception caught!");
                logger.log(Level.ERROR, ((StatusCodeException) e).getStatusCode());
            }
        }
    };
    GWT.setUncaughtExceptionHandler(uncaughtExceptionHandler);
    try {
        // rest of the code in onModule() - I'm expecting any operation to throw StatusCodeException when session times out.
    } catch (RuntimeException ex) {
        uncaughtExceptionHandler.onUncaughtException(ex);
    }
}

This is not working. Instead of getting caught by the code, the StatusCodeException is being displayed on the console. What am I doing wrong here?

The idea is to catch StatusCodeException and use its getStatusCode() method to find out if the HTTP error code is 403. If it is, I want to use Window.Location.assign("https://example.com/redirect"); to redirect them to a login page.


Solution

  •    onFailure(Throwable caught) { 
           logger.error(caught); 
       }
    

    Your AsyncCallback.onFailure is doing exactly what you asked it to do - it is logging the error, but not throwing it. Since it wasn't thrown, the uncaught exception handler doesn't handle it (it can't be not-caught, if it wasn't thrown... if that makes sense).

    One option could be that you could populate the method with throw caught, but java won't like this. Instead, the easiest answer to your specific on is simply to pass it to the handler:

       onFailure(Throwable caught) { 
           GWT.getUncaughtExceptionHandler().onUncaughtException(ex);
       }
    

    One other option you have: since no AsyncCallback will ever throw this, putting the StatusCodeException in the UncaughtExceptionHandler seems a bit odd. Instead, consider making your own AsyncCallback base class, something like this:

    public abstract class NetworkAsyncCallback<T> implements AsyncCallback<T> {
        @Override
        public void onFailure(Throwable t) {
            if (e instanceof StatusCodeException) {
                logger.log(Level.ERROR, "Exception caught!");
                logger.log(Level.ERROR, ((StatusCodeException) e).getStatusCode());
            }
        }
    }
    

    Now, when you make a call, you just have to pass in a new NetworkAsyncCallback<T> and only implement onSuccess. You can skip onFailure if all it was going to do was pass the exceptions to the uncaught handler. Or, if you have some other logic, you can override onFailure, handle the appropriate exceptions, and call super.onFailure(caught) with any other errors so that the superclass handles it.

    myServer.getSomeData(param, new NetworkAsyncCallback<Result>() {
        @Override
        public void onSuccess(Result result) {
            //...
        }
        // Skip onFailure, or if you need custom logic, implement it, 
        // and call super only if the exception isn't part of that logic
    });