A classic one – we find ourselfs in a situation where we have to maintain an existing oData service with very poor error handling. Of course, if we’re there from the start, that won’t happen. Somehow it’s always the other developers who screw this up. This blog post comes for the rescue. We will show a way to implement robust message handling in an oData service that makes implementing error messages a joy through some custom abap classes.
Requirements
Exception Class
We’ll keep it brief here. For our approach, we need an exception class. Create one – if you have no idea how check out Create an Exception Class.
Message Class
Here it is, our message class that will make message handling easy. Through the singleton design pattern we make sure, that one instance handles all messages throughout a request. Let’s take a closer look and go through the different methods:
📟 get_instance
as already described we use the singleton pattern. So we always go for lo_messages = zcl_xxx_messages=>get_instance( ) instead of NEW zcl_xxx_messages
📟 add_bapiret1_to_messages
add a bapiret1 message and decide if an exception should be triggered based on the severity of the message via IV_TRIGGER_EXCEPTION.
📟 add_bapiret2_to_messages
add a bapiret2 message and decide if an exception should be triggered based on the severity of the message via IV_TRIGGER_EXCEPTION.
📟 add_bapiret2_t_to_messages
add bapiret2 messages and decide if an exception should be triggered based on the severity of the messages via IV_TRIGGER_EXCEPTION.
📟 get_messages
get all stored messages
📟 clear_all_messages
clear all messages
📟 errors_exist
check all messages for an error.
Source Code
class ZCL_XXX_MESSAGES definition public final create public . public section. class-methods GET_INSTANCE returning value(RO_INSTANCE) type ref to ZCL_XXX_MESSAGES . methods ADD_BAPIRET1_TO_MESSAGES importing !IS_RETURN type BAPIRETURN1 !IV_TRIGGER_EXCEPTION type BOOLE_D default ABAP_TRUE raising zcx_xxx . methods ADD_BAPIRET2_TO_MESSAGES importing !IS_RETURN type BAPIRET2 !IV_TRIGGER_EXCEPTION type BOOLE_D default ABAP_TRUE raising zcx_xxx . methods GET_MESSAGES returning value(RT_MESSAGES) type BAPIRET2_T . methods ERRORS_EXIST importing !IV_TRIGGER_EXCEPTION type BOOLE_D returning value(RV_ERRORS_EXIST) type BOOLE_D raising zcx_xxx . methods ADD_BAPIRET2_T_TO_MESSAGES importing !IT_RETURN type BAPIRET2_T !IV_TRIGGER_EXCEPTION type BOOLE_D default ABAP_TRUE raising zcx_xxx . methods CLEAR_ALL_MESSAGES . PROTECTED SECTION. PRIVATE SECTION. DATA mt_messages TYPE bapiret2_t . CLASS-DATA mo_instance TYPE REF TO ZCL_XXX_MESSAGES . ENDCLASS. CLASS ZCL_XXX_MESSAGES IMPLEMENTATION. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_XXX_MESSAGES->ADD_BAPIRET1_TO_MESSAGES * +-------------------------------------------------------------------------------------------------+ * | [--->] IS_RETURN TYPE BAPIRETURN1 * | [--->] IV_TRIGGER_EXCEPTION TYPE BOOLE_D (default =ABAP_TRUE) * | [!CX!] zcx_xxx * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD add_bapiret1_to_messages. CHECK is_return IS NOT INITIAL. APPEND INITIAL LINE TO mt_messages ASSIGNING FIELD-SYMBOL(<ls_message>). <ls_message> = CORRESPONDING #( is_return ). IF ( <ls_message>-type EQ 'E' OR <ls_message>-type EQ 'A' ) AND iv_trigger_exception EQ abap_true. RAISE EXCEPTION TYPE zcx_xxx. ENDIF. ENDMETHOD. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_XXX_MESSAGES->ADD_BAPIRET2_TO_MESSAGES * +-------------------------------------------------------------------------------------------------+ * | [--->] IS_RETURN TYPE BAPIRET2 * | [--->] IV_TRIGGER_EXCEPTION TYPE BOOLE_D (default =ABAP_TRUE) * | [!CX!] zcx_xxx * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD add_bapiret2_to_messages. CHECK is_return IS NOT INITIAL. APPEND is_return TO mt_messages. IF ( is_return-type EQ 'E' OR is_return-type EQ 'A' ) AND iv_trigger_exception EQ abap_true. RAISE EXCEPTION TYPE zcx_xxx. ENDIF. ENDMETHOD. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_XXX_MESSAGES->ADD_BAPIRET2_T_TO_MESSAGES * +-------------------------------------------------------------------------------------------------+ * | [--->] IT_RETURN TYPE BAPIRET2_T * | [--->] IV_TRIGGER_EXCEPTION TYPE BOOLE_D (default =ABAP_TRUE) * | [!CX!] zcx_xxx * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD add_bapiret2_t_to_messages. DATA: ls_return TYPE bapiret2. CHECK it_return IS NOT INITIAL. mt_messages = CORRESPONDING #( BASE ( mt_messages ) it_return ). LOOP AT it_return INTO ls_return. IF ( ls_return-type EQ 'E' OR ls_return-type EQ 'A' ) AND iv_trigger_exception EQ abap_true. RAISE EXCEPTION TYPE zcx_xxx. ENDIF. ENDLOOP. ENDMETHOD. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_XXX_MESSAGES->CLEAR_ALL_MESSAGES * +-------------------------------------------------------------------------------------------------+ * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD clear_all_messages. CLEAR mt_messages. ENDMETHOD. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_XXX_MESSAGES->ERRORS_EXIST * +-------------------------------------------------------------------------------------------------+ * | [--->] IV_TRIGGER_EXCEPTION TYPE BOOLE_D * | [<-()] RV_ERRORS_EXIST TYPE BOOLE_D * | [!CX!] zcx_xxx * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD errors_exist. LOOP AT mt_messages ASSIGNING FIELD-SYMBOL(<ls_message>) WHERE type EQ 'E' OR type EQ 'A'. rv_errors_exist = abap_true. IF iv_trigger_exception EQ abap_true. RAISE EXCEPTION TYPE zcx_xxx. ENDIF. ENDLOOP. ENDMETHOD. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_XXX_MESSAGES=>GET_INSTANCE * +-------------------------------------------------------------------------------------------------+ * | [<-()] RO_INSTANCE TYPE REF TO ZCL_XXX_MESSAGES * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD get_instance. IF mo_instance IS INITIAL. CREATE OBJECT mo_instance. ENDIF. ro_instance = mo_instance. ENDMETHOD. * <SIGNATURE>---------------------------------------------------------------------------------------+ * | Instance Public Method ZCL_XXX_MESSAGES->GET_MESSAGES * +-------------------------------------------------------------------------------------------------+ * | [<-()] RT_MESSAGES TYPE BAPIRET2_T * +--------------------------------------------------------------------------------------</SIGNATURE> METHOD get_messages. rt_messages = mt_messages. ENDMETHOD. ENDCLASS.
How to use the message handling class in your abap code
In the following code snippet there is an example of how to use the approach.
CLASS lcl_test DEFINITION FINAL. PUBLIC SECTION. CLASS-METHODS get_expanded_entity IMPORTING is_entity TYPE zhr_gw_entity_s EXPORTING et_return TYPE bapiret2_t es_entity TYPE zhr_gw_entity_s. CLASS-METHODS execute_business_logic IMPORTING iv_param TYPE string RETURNING VALUE(rs_entity) TYPE zhr_gw_entity_s RAISING zcx_xxx. ENDCLASS. CLASS lcl_test IMPLEMENTATION. METHOD get_expanded_entity. DATA: lt_messages TYPE REF TO zcl_xxx_messages. lo_messages = zcl_xxx_messages=>get_instance( ). TRY. es_entity = execute_business_logic( iv_param = is_entity-param ). CATCH zcx_xxx. et_return = lo_messages->get_messages( ). ENDTRY. ENDMETHOD. METHOD execute_business_logic. DATA: lo_messages TYPE REF TO zcl_xxx_messages, lv_msg TYPE bapi_msg, ls_return TYPE bapiret2. lo_messages = zcl_xxx_messages=>get_instance( ). "execute business logic here *--- sample for throwing an exception/error message MESSAGE e001(zxxx) INTO lv_msg. ls_return = VALUE #( type = sy-msgty id = sy-msgid number = sy-msgno message = lv_msg ). lo_messages->add_bapiret2_to_messages( is_return = ls_return ). ENDMETHOD. ENDCLASS.
