3.2.12.3. Client-Level Exception Handlers
Unhandled exceptions thrown on the client tier or passed from Middleware, are passed to the special handlers mechanism of the Web Client block.
A handler is a managed 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 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 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:
package com.company.demo.web;
public class ZeroBalanceException extends RuntimeException {
public ZeroBalanceException() {
super("Insufficient funds in your account");
}
}
Then the handler for this exception must have the following constructor:
@Component("demo_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("sample_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 doHandle()
method and looks as follows:
package com.company.demo.web;
import com.haulmont.cuba.gui.Notifications;
import com.haulmont.cuba.gui.exception.AbstractUiExceptionHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Nullable;
@Component("demo_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 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:
package com.company.demo.web.exceptions;
import com.haulmont.cuba.gui.Notifications;
import com.haulmont.cuba.gui.exception.AbstractUiExceptionHandler;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Nullable;
@Component("demo_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();
}
@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();
}
}