Start of Content Area

Background documentation Planning Exception Handling and Delegating Exceptions  Locate the document in its SAP Library structure

Catching and Handling Exceptions

A TRY-ENDTRY structure can contain several handlers and you can catch exceptions of different classes in a handler. Furthermore, with the exceptions of a class, you can also catch all exceptions of any subclasses of this class. In this way, exceptions can be handled in groups. For example, you can decide to raise different exceptions depending on whether a specific customer address exists, is invalid, or exists multiple times, but then assign all these exceptions to a common superclass and catch the superclass.

You catch exceptions using a CATCH structure that contains the name of the relevant exception class or a class higher up in the inheritance hierarchy. You can handle exceptions that have been caught. Handlers should be implemented so that they react to errors accordingly and ensure that the program can continue to run correctly. However, in a modularized program, this is not always possible at the point where the exception was raised.

Delegating Exception Handling

Let us imagine you want to write a service class that manages address data on the database. A method receives the key of a specific business object and is to read the relevant data from the database. If no address is found, you should raise an exception, but it should not be handled immediately in your method. Not that this would be possible anyway. You do not know what the caller intends to do with the address, that is, whether it is just additional information – for example, for the agents of a call center – or whether the program flow would have to be significantly changed without this data – for example, in the case of a delivery, for which a delivery address is essential.

Declaring Exceptions at the Interface

For this reason, it is important that you, as a developer of modularized units, can delegate exceptions to the caller. The process of passing exceptions up the call hierarchy, known as propagation, occurs automatically whenever an exception is not handled in the TRY-ENDTRY structure in which it was raised. However, the exceptions must be declared at the interface of a procedure (method, subroutine, function module). Otherwise syntax errors will occur at design time and the exception CX_SY_NO_HANDLER will be raised at runtime. In this way, the runtime environment ensures that only declared exceptions can exit a procedure (special exceptions to this rule will be covered later).

Why do exceptions have to be declared? The caller of a method has to know what exceptions to expect. The caller is not usually interested in the inner workings of the called method and the methods called there concern the caller even less. The declaration at the interface ensures that you, as the caller of a procedure, can be certain about which exceptions you must handle and which you must pass on.

CLEANUP Block

If you do not handle an exception in your program unit, and the control flow jumps from the raised location up to a point in the call hierarchy where it can be handled, the program unit may be left in an inconsistent state and some resources may be overloaded. The CLEANUP block is intended for such situations. The CLEANUP block of a TRY-ENDTRY structure is only processed if:

·        The exception is raised in the protected area of this structure

·        The exception is not handled in this structure, but there is a handler further up in the call hierarchy. If the exception is not caught anywhere, it is important not to erase any traces of the error. Therefore, the CLEANUP block is not processed in these cases.

Under no circumstances should you attempt to exit a CLEANUP block prematurely using RETURN, EXIT, or CONTINUE. The CLEANUP block is processed on the basis of the confirmation that the error is handled further up the hierarchy. Leaving it prematurely could result in this confirmation being violated. Therefore, a runtime error is triggered if you attempt to exit a CLEANUP block prematurely.

Planning Exception Handling Locally

If you are writing reusable software, you should only plan the exception handling for the program unit you are writing. You should, as much as possible, avoid making specific assumptions about the calling layers or those that you call, if these assumptions go beyond the scope of the contract specified in the interface. The implementation of these layers could change, and then your exception handling may no longer function correctly if it depended on assumptions about the inner workings of these layers and these assumptions no longer exist at a later stage.

You should simply decide the following for your procedure: Which of the exceptions that you raise or receive from lower down the hierarchy do you want to handle and which do you want to delegate, that is, propagate. When you handle exceptions, you have to be particularly careful with messages or other means of passing information to the user interface. Avoid it if you are not completely sure that your program unit makes up the user interface.

Handlers

You handle an exception in a handler, of course. However, your actions in each case can be very different. An analogy to an interrupted journey may help to clarify what appropriate exception handling involves. Imagine you are unable to continue along your travel route, because a bridge across a river is closed. This represents the error situation. There are different ways of reacting:

·        You can use a different bridge and still reach your goal despite taking a detour. The analogy in the case of the program would be to recalculate required values in a cache.

·        You can abort your day trip and continue with what you had planned for the next day. If an ERP application cannot continue listing a delivery because the price of a product is missing, the control flow of the program can simply move on to the next product.

·        If there is no other bridge to be found and the rest of your journey is not possible as you cannot cross the river, you may decide to abort the entire trip. This can be compared to the case where an error in the program flow is so severe that it would be best to stop the program.

There is one task you will often carry out in the handler for which there is no equivalent in this analogy: Sometimes, an exception is raised with a very technical text and you want to pass this exception up the call hierarchy, but here a text is required that the end user can understand. In this case, you catch the original exception, raise a new one that the end user can understand, and attach a reference to the old exception to the new exception as an attribute. This is known as mapping one exception onto another.

You should only pass information about an exception to the user if you are completely sure that the component you are writing is in a suitable layer. If your component is called far away from the user interface, passing a text directly to the user in the case of an exception would not be advisable. Instead, you could handle the technical side of the exception and delegate an exception with a new text further up the hierarchy.

 

End of Content Area