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.
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.
No comments:
Post a Comment