Exception handling

Completed

While conditional statements are great for handling the running of different code blocks, exception handling is used to deal with errors. Statements like throw, try...catch, finally, and retry can be used to handle exceptions. An exception is a way for the code to jump away from the runnable code when an error occurs.

The throw statement can be used to give an error exception. A throw statement can specify an exception enum value, but it is best practice to use the global error, info, or warning methods. This method allows you to use a label to display to the user in an Infolog, as shown in the following example:

throw error("This is an error.");

Here is what an error, warning, and info message looks like in the user interface:

Screenshot showing error, warning, and info messages.

Static methods on the Global class can be called without the Global:: prefix, so the Global::error method can also be called as shown in the following example:

error("This is an error.");

You can also use a try...catch statement to process some code in the try block, and then use the catch block to handle an exception if it occurs. In the following example, the try block runs some code. If a numeric exception occurs, the first catch block gives an info message to display: "Found a Numeric." The second catch block handles any other errors that might be found. You should only catch exceptions that you know your code inside the try block might throw. All other exceptions should rise to the next stack frame.

try
{
	//Run some code that might throw a numeric or other type of exception.
}
catch (Exception::Numeric)
{
	info('Found a Numeric exception.');
}
catch
{
	info('Caught an exception');
	retry;
}
finally
{
        // Executed no matter how the try block exits.
}

A retry can be written in a catch block to jump back to the first line of code within the try block. This can be used if the issue in the implementation can be fixed by code in the catch block. Then, the try block will run again to give it a second chance to succeed. Make sure that the retry does not cause an infinite loop. A finally clause can be added to a try...catch statement. Statements in the finally clause are run when the implementation of the code leaves the try block. The statements in the finally block will run no matter how the try block exits.

If an exception is not handled, then the call to the current method is unraveled and the exception will be handled, or not handled, in the caller's scope.

User messages

By using the Message() API, you can have more control over the lifecycle of a message, you can explicitly add and remove messages. This can be used if you need validation messages removed at times other than when a save boundary has been crossed, or for displaying an informational message about a specific aspect of the user’s experience that is directly related to data validation.

Let’s look at an example:

messageId = Message::Add(MessageSeverity::Informational, "The customer is marked as inactive");

In this example, the message can then be cleared when a new record is shown on the page.

In addition to using the Message() API, you can use the Message::AddAction() method so you can embed an action within a message that is sent to the message bar. This method supports adding a single action that is associated with a display or action menu item, that can then be visualized as a Link button.

In the following example, a message is triggered for a system administrator letting them know that a batch job is not running and then exposes an action to go directly to the Batch jobs page.

MenuItemMessageAction actionData = new MenuItemMessageAction();

actionData.MenuItemName("BatchJob");

str jsonData = FormJsonSerializer::serializeClass(actionData);

int64 messageId = Message::AddAction(MessageSeverity::Informational, "The Test batch job is not currently running", "Go to Batch jobs", MessageActionType::DisplayMenuItem, jsonData);

Here is the output:

Screenshot showing the  output message The test batch job is not currently running.

Exceptions inside transactions

If an exception is thrown inside a transaction, the transaction is automatically aborted (a ttsAbort operation occurs). This applies for exceptions that are thrown manually and for exceptions that are thrown by the system.

When an exception is thrown inside a ttsBegin - ttsCommit transaction block, no catch statement inside that transaction block can process the exception. Instead, the innermost catch statements that are outside the transaction block are the first catch statements to be tested.