5.2.12.3. Client-Level Exception Handlers

Unhandled exceptions in Web Client and Desktop Client blocks thrown on the client tier or passed from Middleware, are passed to the special handlers mechanism. This mechanism is implemented in the gui module and available for both blocks.

The handler should be a managed bean implementing the GenericExceptionHandler interface, handle processing in its handle() method and return true, or immediately return false, if this handler is not able to handle the passed exception. This behaviour enables creating a "chain of responsibility" for handlers.

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

@Component("cuba_EntityAccessExceptionHandler")
public class EntityAccessExceptionHandler extends AbstractGenericExceptionHandler {

    public EntityAccessExceptionHandler() {
        super(EntityAccessException.class.getName());
    }
...

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

@Component("cuba_OptimisticExceptionHandler")
public class OptimisticExceptionHandler extends AbstractGenericExceptionHandler implements Ordered {

    public OptimisticExceptionHandler() {
        super("javax.persistence.OptimisticLockException");
    }
...

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

@Override
protected void doHandle(String className, String message, @Nullable Throwable throwable, WindowManager windowManager) {
    String msg = messages.getMainMessage("zeroBalance.message");
    windowManager.showNotification(msg, IFrame.NotificationType.ERROR);
}

If the name of the exception class is insufficient to make a decision whether this handler can be applied to the exception, canHandle() method should be defined. 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("cuba_NumericOverflowExceptionHandler")
public class NumericOverflowExceptionHandler extends AbstractGenericExceptionHandler {

    public NumericOverflowExceptionHandler() {
        super(EclipseLinkException.class.getName());
    }

    @Override
    protected boolean canHandle(String className, String message, @Nullable Throwable throwable) {
        return StringUtils.containsIgnoreCase(message, "Numeric field overflow");
    }
...

WindowManager provides a method for showing an exception with its stack trace: showExceptionDialog(). The method has the following parameters:

  • throwable - Throwable instance.

  • caption - dialog caption. It is an optional parameter, if not set, the default caption is used.

  • message - dialog message. It is an optional parameter, if not set, the default caption is used.

An example of using the method in an exception handler:

@Override
protected void doHandle(String className, String message, @Nullable Throwable throwable, WindowManager windowManager) {
    if (throwable != null)
        windowManager.showExceptionDialog(throwable, "Exception is thrown", message);
    else
        windowManager.showNotification(message, IFrame.NotificationType.ERROR);
}