Skip to Content

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.

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

  1. Fabian Lupa

    Thanks for the blog! Some additional thoughts of mine:

    In ABAP 750 you can use the new interface IF_T100_DYN_MSG for this exact conversion. Take a look at this blog post for some details (there’s also a way described with < 750).

    I personally have stopped using static helper methods to raise exceptions and instead use the RAISE EXCEPTION statement directly at the point where it is needed. While that may introduce some necessary boilerplate code (i. e. the condition to check if the exception should be raised) it has the advantage that you can jump to the RAISE EXCEPTION statement in the debugger when the exception occurs. With static helper methods you can abstract away the condition but unfortunately you always jump to the static helper methods’ RAISE statement instead.

    (4) 

Leave a Reply