Exception handling

Documents for the development of and with JVx.

Exception handling

Postby Development@SIB » Fri Jul 21, 2017 11:44 am

Exception handling is very important for applications. It's necessary to visualize unexpected exceptions and to handle expected exceptions. But exception handling should be easy, centralized and shouldn't blow up the application code. Isn't it boring to catch Exceptions after unimportant code blocks?

This could be boiler-plate code:

Syntax: [ Download ] [ Hide ]
try
{
    Email email = prepareEmail(dataBook);

    sendEmail(email);
}
catch (MessagingException me)
{
    showError(me);
}

If you catch Exceptions to show error messages, it's boiler-plate code. If you catch exceptions to do specific error handling, it's not. Usually an application has both use-cases.

With JVx, we tried to reduce code for exception handling to a bare minimum. We delegate "all" framework exceptions to an ExceptionHandler. The ExceptionHandle is more or less a delegator.

The ExceptionHandler doesn't visualize an exception. It forwards exceptions to a listener list and is responsible for logging. The application itself is reponsible for visualization because only the application knows how to visualize an exception - as Popup, as status in a specific area, ...

The standard JVx application already supports visualization of exceptions because it's a registered exception listener. The method

Syntax: [ Download ] [ Hide ]
public void handleException(Throwable pThrowable)
{
    error(pThrowable);
   
    try
    {
        if (error == null || error.isClosed())
        {
            error = createError();
            error.eventWindowClosed().addListener(this, "doErrorClosed");

            configureFrame(error);
           
            invokeLater(this, "showErrorDialog");
        }

        error.addError(pThrowable);
    }
    catch (Throwable th)
    {
        //forwarding to the launcher is the only possibility
        getLauncher().handleException(th);
       
        getLauncher().handleException(pThrowable);
    }
}

will do the job. Simply override the method to do what you want or register your own listener and remove the application ans exception listener.

The default implementation makes is super easy to show exceptions without additional code. Suppose we have following action:

Syntax: [ Download ] [ Hide ]
UIButton button = new UIButton("Send E-Mail");
button.eventAction().addListener(this, "doSendEmail");

public void doSendEmail()
{
    getConnection().callAction("sendEmail");
}

The callAction method will throw Throwable because it's a remote procedure call and all remote procedure calls will throw Throwable instead of an Exception. JVx doesn't define custom exceptions because Java has enough and it wasn't necessary to wrap exceptions for remote calls. The application is able to define custom exceptions in remote procedure calls, but JVx doesn't wrap exceptions. It's nice for an application developer to get the thrown exception instead of unwrapping a catched exception to get the original exception.

To make our action working, we could do following:
Syntax: [ Download ] [ Hide ]
public void doSendEmail() throws Throwable
{
    getConnection().callAction("sendEmail");
}

It's good enough to add throws Throwable to the method definition. The event mechanism of JVx will do the rest, because it forwards exceptions to ExceptionHandler:

Syntax: [ Download ] [ Hide ]
@Override
public Object dispatchEvent(Object... pEventParameter)
{
    try
    {
        return super.dispatchEvent(pEventParameter);
    }
    catch (Throwable pThrowable)
    {
        ExceptionHandler.raise(pThrowable);
        return null;
    }
}

If you need custom exception handling, simply do it:

Syntax: [ Download ] [ Hide ]
public void doSendEmail() throws Throwable
{
    try
    {
        getConnection().callAction("sendEmail");
    }
    catch (MessagingException me)
    {
        showEmailProblem(me);
    }
}

This will handle MessagingException and all other exceptions will be handled from the default implementation. But it's also possible to ignore the default implementation:

Syntax: [ Download ] [ Hide ]
public void doSendEmail()
{
    try
    {
        getConnection().callAction("sendEmail");
    }
    catch (MessagingException me)
    {
        showEmailProblem(me);
    }
    catch (Throwable th)
    {
        handleProblem(th);
    }
}

Please, centralize your custom exception handling to keep things simple and to reduce complexity.

It's also possible to use standard exception visualization from your custom code:

Syntax: [ Download ] [ Hide ]
public void doSendEmail()
{
    try
    {
        getConnection().callAction("sendEmail");
    }
    catch (MessagingException me)
    {
        showEmailProblem(me);
    }
    catch (Throwable th)
    {
        ExceptionHandler.show(th);
    }
}

The ExceptionHandler has two relevant methods for your exceptions:

Syntax: [ Download ] [ Hide ]
public static void raise(Throwable pThrowable)
public static void show(Throwable pThrowable)

The raise method will interrupt code execution and show will continue.

The ExceptionHandler knows one specific Exception which will be handled separately. It's the SilentAbortException. If you throw a SilentAbortException, no listener will be notified about the exception. This also means that your application doesn't visualize the exception.
User avatar
Development@SIB
 
Posts: 311
Joined: Mon Sep 28, 2009 1:54 pm

Return to Documentation