Although function modules belong to the era of procedural programming, we all need to use them from time to time. While most BAPI’s usually return error messages in a clean internal table format, many other function modules return classical exceptions.
If you are calling a function within a class method, you might have a hard time converting those classical exceptions to class based exceptions – meaning exception classes.
I have written an exception class which automatically converts any function module exception to a class based exception. Here is the source code:
CLASS zcx_bc_function_subrc DEFINITION PUBLIC INHERITING FROM cx_static_check FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_t100_message . CONSTANTS: BEGIN OF subrc_error," Function &1 error &2 : &3 - &4 msgid TYPE symsgid VALUE 'ZBC', msgno TYPE symsgno VALUE '130', attr1 TYPE scx_attrname VALUE 'FUNCNAME', attr2 TYPE scx_attrname VALUE 'SUBRC', attr3 TYPE scx_attrname VALUE 'PARAM', attr4 TYPE scx_attrname VALUE 'STEXT', END OF subrc_error. DATA: funcname TYPE funct-funcname, subrc TYPE sysubrc, param TYPE funct-parameter, stext TYPE funct-stext. METHODS constructor IMPORTING !textid LIKE if_t100_message=>t100key OPTIONAL !previous LIKE previous OPTIONAL !funcname TYPE funct-funcname OPTIONAL !subrc TYPE sysubrc DEFAULT sy-subrc !param TYPE funct-parameter !stext TYPE funct-stext. CLASS-METHODS raise_if_sysubrc_not_initial IMPORTING !iv_funcname TYPE funct-funcname RAISING zcx_bc_function_subrc. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcx_bc_function_subrc IMPLEMENTATION. METHOD constructor. CALL METHOD super->constructor EXPORTING previous = previous. CLEAR me->textid. IF textid IS INITIAL. if_t100_message~t100key = if_t100_message=>default_textid. ELSE. if_t100_message~t100key = textid. ENDIF. me->funcname = funcname. me->subrc = subrc. me->param = param. me->stext = stext. ENDMETHOD. METHOD raise_if_sysubrc_not_initial. CHECK sy-subrc IS NOT INITIAL. DATA(lv_subrc_bak) = sy-subrc. SELECT SINGLE parameter INTO @DATA(lv_parameter) FROM fupararef WHERE funcname EQ @iv_funcname AND paramtype EQ @abap_true AND pposition EQ @lv_subrc_bak. SELECT SINGLE stext INTO @DATA(lv_stext) FROM funct WHERE spras EQ @sy-langu AND funcname EQ @iv_funcname AND parameter EQ @lv_parameter AND kind EQ @abap_true. IF sy-subrc NE 0. SELECT SINGLE stext INTO @lv_stext FROM funct WHERE funcname EQ @iv_funcname AND parameter EQ @lv_parameter AND kind EQ @abap_true. ENDIF. RAISE EXCEPTION TYPE zcx_bc_function_subrc EXPORTING funcname = iv_funcname param = lv_parameter stext = lv_stext subrc = lv_subrc_bak textid = zcx_bc_function_subrc=>subrc_error. ENDMETHOD. ENDCLASS.
Here is an example of making this exception class useful.
CLASS zcl_sample DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. METHODS sample_method RAISING zcx_bc_function_subrc. PRIVATE SECTION. PROTECTED SECTION. ENDLCASS. CLASS zcl_sample IMPLEMENTATION. METHOD sample_method. CALL FUNCTION 'ZFUNCTION' EXPORTING IV_PARAM1 = 'DUMMY' EXCEPTIONS some_error = 1 another_error = 2 OTHERS = 3 ##FM_SUBRC_OK . zcx_bc_function_subrc=>raise_if_sysubrc_not_initial( 'ZFUNCTION' ). ENDMETHOD. ENDCLASS.
The static method RAISE_IF_SYSUBRC_NOT_INITIAL will do nothing if SY-SUBRC is initial. Otherwise, it will determine the details of the function exception and raise a class based exception using that information.
Since the static method is based on SY-SUBRC, it must be placed immediately after the function call – before anything else changes SY-SUBRC.
The pragma ##FM_SUBRC_OK tells the ABAP checker that we intentionally didn’t check SY-SUBRC after the function call. We check it within the static method, but the checker wouldn’t know that.
The advantage of this method is; you don’t need to develop a custom class based exception for each function module. It would simply work with any function. The disadvantage is; it consolidates all exceptions into a single class (ZCX_BC_FUNCTION_SUBRC) so the details of the error are not easy to determine programatically. The details of the functional exception is stored as a text within the exception class and you can’t include any other variables.
Nevertheless; this is a practical approach if you don’t need all the bells & whistles and simply need to return a casual exception object in case the function returns an error.
Leave a Reply