In this article I’d like to present a solution how to implement a global class where all internal exceptions (exceptions raised by private methods only ⇒ always catched within the class itself) will be handled with its local exception class.
It is generally possible (and recommended) to use global exception classes but sometimes you can find a local exception class be more practical (no DDIC entries, no heavy coding/maintenance, …).
I wanted a simple solution supporting WHERE-USED functionality for all messages defined in SE91 which can be generated in my program’s exceptions.
Sadly it is not possible to create a local exception class in a global class’s “local definitions” section AND use it in the global class method’s EXCEPTIONS section (by default). This is because the class editor’s compiler does NOT see this local exception class as will be demonstrated in the following few steps.
You maybe noticed the “by default” note in the previous paragraph – this will be explained in the following paragraphs…
Navigation to the global class’s local definitions & implementations:
Here follows our local exception class definition which I entered in the “Local Class Definitions/Types” section
CLASS lcx_exception DEFINITION INHERITING FROM cx_static_check. PUBLIC SECTION. METHODS: constructor, get_text REDEFINITION. CLASS-DATA: * Statically accessible variable - the reason will be shown later message TYPE bapiret2-message. PRIVATE SECTION. DATA: mv_message TYPE bapiret2-message. ENDCLASS.
I keep the local exception class implementation very simple:
CLASS lcx_exception IMPLEMENTATION. METHOD constructor. super->constructor( ). * Save the static variable to instance variable me->mv_message = lcx_exception=>message. ENDMETHOD. METHOD get_text. * Return message from the instance variable result = me->mv_message. ENDMETHOD. ENDCLASS.
Now I’m trying to create new class method (called e.g. TEST_METHOD), which would like to raise exceptions of type LCX_EXCEPTION – you can see the system reacts with popup message saying that such exception class is NOT KNOWN!!!
…so the system offers to create a new GLOBAL exception class – but this is not what we wanted.
Therefore the class method must raise a generic exception (e.g. CX_STATIC_CHECK) or a global exception from which your local exception class is inheriting from (by default).
Did you notice the “by default” note again in paragraph above?
It is a “dark corner” of the “Form-based” class editor. This means that the form-based editor can be very nice, intuitive, easy to navigate, … BUT…
It is apparently missing some functionalities offered in the “Source code-based” editor.
Just try switching to the source-based editor in SE24, put your local exception class (not the CX_STATIC_CHECK) in the RAISING section of the class-method and try to compile your code.
WHAT, IT WORKS???!!!
Now with equanimity you can switch back to the form-based editor and continue working as you were used to – the compiler won’t scream again unless you modify the EXCEPTIONS section of the class-method raising the local exception.
But in such case you can re-do this “source-editor trick” againg of course.
In the caller method (called e.g. RUN_TEST) you handle the exception occurrence like it was of you local exception class type.
Note: For testing purpose I created method RUN_TEST as Instance & Public so I can execute it directly with F8.
METHOD run_test. DATA: lr_my_exception TYPE REF TO lcx_exception, lr_static_exception TYPE REF TO cx_static_check, lv_message TYPE bapiret2-message. TRY. me->test_method( ). * Catch my locally defined exception CATCH lcx_exception INTO lr_my_exception. lv_message = lr_my_exception->get_text( ). WRITE lv_message. * Catch any other exception of type CX_STATIC_CHECK CATCH cx_static_check INTO lr_static_exception. lv_message = lr_static_exception->get_text( ). WRITE lv_message. ENDTRY. ENDMETHOD.
The code of the TEST_METHOD would be like this:
METHOD test_method. MESSAGE e001(ztest) WITH 'ZCL_EXCEPTION_DEMO-TEST_METHOD' INTO lcx_exception=>message. RAISE EXCEPTION TYPE lcx_exception. ENDMETHOD.
Important note: In the above code please note the MESSAGE command. Thanks to this command the SAP system is able to find usage of the applied message with the WHERE-USED functionality from SE91
For testing purposes I prepared a simple program that tests our solution:
REPORT zr_test_local_exceptions. DATA: lr_demo TYPE REF TO zcl_exception_demo. START-OF-SELECTION. CREATE OBJECT lr_demo. lr_demo->run_test( ).
…and here comes the output: