Exception Handlers

Unhandled exceptions thrown on the client are passed to the special handlers mechanism.

An exception handler is a Spring bean implementing the UiExceptionHandler interface. Its handle() method should process the exception and return true, or immediately return false if this handler is not able to handle the passed exception. This behavior enables creating a "chain of responsibility" for handlers.

It is recommended to inherit your handlers from the AbstractUiExceptionHandler base class, which can disassemble the exceptions chain (including ones packed inside RemoteException) and handle specific exception types. Exception types supported by this handler are defined by passing a string array to the base constructor from the handler constructor. Each string of the array should contain one full class name of the handled exception.

Suppose you have the following exception class:

public class ZeroBalanceException extends RuntimeException {

    public ZeroBalanceException() {
        super("Insufficient funds in your account");
    }
}

Create the handler for this exception with the following constructor:

@Component("uiex1_ZeroBalanceExceptionHandler")
public class ZeroBalanceExceptionHandler extends AbstractUiExceptionHandler {

    public ZeroBalanceExceptionHandler() {
        super(ZeroBalanceException.class.getName());
    }
}

If the exception class is not accessible on the client-side, specify its name with the string literal:

@Component("uiex1_ForeignKeyViolationExceptionHandler")
public class ForeignKeyViolationExceptionHandler extends AbstractUiExceptionHandler {

    public ForeignKeyViolationExceptionHandler() {
        super("java.sql.SQLIntegrityConstraintViolationException");
    }
    /*...*/
}

In the case of using AbstractUiExceptionHandler as a base class, the processing logic is located in the doHandle() method and looks as follows:

@Component("uiex1_ZeroBalanceExceptionHandler")
public class ZeroBalanceExceptionHandler extends AbstractUiExceptionHandler {

    public ZeroBalanceExceptionHandler() {
        super(ZeroBalanceException.class.getName());
    }
    @Override
    protected void doHandle(String className, String message,
                            @Nullable Throwable throwable, UiContext context) {
        context.getNotifications().create(Notifications.NotificationType.ERROR)
                .withCaption("Error")
                .withDescription(message)
                .show();
    }
}

If the name of the exception class is insufficient to make a decision on whether this handler can be applied to the exception, define the canHandle() method. This method accepts also the text of the exception. If the handler is applicable for this exception, the method must return true. For example:

@Component("uiex1_ZeroBalanceExceptionHandler")
public class ZeroBalanceExceptionHandler extends AbstractUiExceptionHandler {

    /*...*/

    @Override
    protected boolean canHandle(String className, String message,
                                @Nullable Throwable throwable) {
        return StringUtils.containsIgnoreCase(message,
                "Insufficient funds in your account");
    }
}

The Dialogs interface available via the UiContext parameter of the doHandle() method provides a special dialog for displaying exceptions containing a collapsable area with the complete exception stack trace. This dialog is used in the default handler, but you can use it for your exceptions too, for example:

@Override
protected void doHandle(String className, String message,
                        @Nullable Throwable throwable, UiContext context) {
    if (throwable != null) {
        context.getDialogs().createExceptionDialog()
                .withThrowable(throwable)
                .withCaption("Error")
                .withMessage(message)
                .show();
    } else {
        context.getNotifications().create(Notifications.NotificationType.ERROR)
                .withCaption("Error")
                .withDescription(message)
                .show();
    }
}