[ABAP] OO: Lokale Exception-Klasse anlegen, auslösen und behandeln, Nutzung des Interfaces if_t100_message

* http://havliczech.blogspot.com/2014/07/local-exception-class-message.html

* lokale Exceptionklasse
CLASS lcx_my_exception DEFINITION INHERITING FROM cx_static_check FINAL CREATE PUBLIC.
  PUBLIC SECTION.

* von Interface if_t100_message ableiten
    INTERFACES if_t100_message.

    DATA: methname TYPE string READ-ONLY ##NEEDED.
    DATA: msg      TYPE string READ-ONLY ##NEEDED.
    DATA: code     TYPE char2  READ-ONLY ##NEEDED.

    METHODS constructor
      IMPORTING methname TYPE sys_calls-eventname
                msg      TYPE string
                code     TYPE char2.
ENDCLASS.

CLASS lcx_my_exception IMPLEMENTATION.

* Übergabe der Parameter erfolgt im Conructor
  METHOD constructor.
    super->constructor( ).

    me->methname = methname.
    me->msg      = msg.
    me->code     = code.

* Standard Message-Typ verwenden: & & & &
    me->if_t100_message~t100key-msgid = 'SY'.
    me->if_t100_message~t100key-msgno = '499'.
    me->if_t100_message~t100key-attr1 = 'METHNAME'.
    me->if_t100_message~t100key-attr2 = 'MSG'.
    me->if_t100_message~t100key-attr3 = 'CODE'.
    me->if_t100_message~t100key-attr4 = ''.
  ENDMETHOD.

ENDCLASS.

* Testklasse zum Auslösen der Exception
CLASS lcl_demo DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      div
        IMPORTING i_val1        TYPE f
                  i_val2        TYPE f
        RETURNING VALUE(rv_ret) TYPE f
* Propagieren der Exception
        RAISING   lcx_my_exception.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.
  METHOD div.
    IF i_val2 = '0.0'.
* Wenn durch 0.0 geteilt werden soll: Auslösen der lokalen Exception, zusätzlichen Parameter übergeben
      RAISE EXCEPTION TYPE lcx_my_exception
        EXPORTING
          methname = 'DIV'
          msg      = 'Division durch 0'
          code     = 'DD'.
    ELSE.
      rv_ret = i_val1 / i_val2.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  TRY.
* durch 0.0 teilen -> Exception wird ausgelöst
      WRITE: / lcl_demo=>div( i_val1 = '1.1'
                              i_val2 = '0.0' ).
* Abfangen der lokalen Exception
    CATCH lcx_my_exception INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] Fehlermeldungen über die Standard-Exceptionklasse CX_T100_MSG ausgeben

* Auslösen der Exeption CX_T100_MSG
CLASS zxyz DEFINITION FINAL.

  PUBLIC SECTION.

    METHODS: constructor
      IMPORTING
        !iv_text TYPE string " Übergabestring für Test
      RAISING
        cx_t100_msg.         " Fehler im Konstruktor löst evtl. CX_T100_MSG aus

ENDCLASS.

CLASS zxyz IMPLEMENTATION.
  METHOD constructor.

    IF NOT iv_text IS INITIAL.

      ...

    ELSE.
* Wenn iv_text leer -> CX_T100_MSG auslösen
      RAISE EXCEPTION TYPE cx_t100_msg
        EXPORTING
          t100_msgid = '00'
          t100_msgno = '398'
          t100_msgv1 = 'Text war leer.' " 1. String
          t100_msgv2 = ''               " 2. String
          t100_msgv3 = ''               " 3. String
          t100_msgv4 = ''.              " 4. String
    ENDIF.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
* Exception CX_T100_MSG abfangen
  TRY.
* zum Auslösen der Exception den Übergabeparameter leer lassen
      DATA(o_test) = NEW zxyz( iv_text = '' ).
* Exception abfangen
    CATCH cx_root INTO DATA(e_txt).
* Klassenname
      WRITE: / cl_abap_classdescr=>get_class_name( p_object = e_txt ).
* Messagetext
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] CX_T100_MSG: Einfache Erstellung und Nutzung einer globalen Exception-Klasse, mit Definition eigener Nachrichten-IDs

Nutzung von SAP-Standard-Klasse CX_T100_MSG, Definition eigener Nachrichten-IDs

  • Ausnahmeklasse anlegen
  • Verwendung der vorhandenen und frei verwendbaren T100-Text-ID: 00 398 “& & & &”
    1. SE80 Projekt -> Klassen -> Anlegen
      • Klassenname: ZCX_MY_EXCEPTION
      • Oberklasse: CX_T100_MSG
      • Klassentyp: Ausnahmeklasse mit Haken bei “Nachrichtenklasse”
      • Interfaces: “IF_T100_MESSAGE” wird automatisch hinzugefügt
    2. Klasse / Interface: ZCX_MY_EXCEPTION
      • Reiter “Texte”
      • neue Ausnahme-ID (Text-ID) hinzufügen: MY_OBJECT_NOT_FOUND
      • auf Button “Nachrichtentext” klicken
      • entweder eigene Z-Nachrichtenklasse mit Nachrichtennummern und Nachrichtenkurztexten pflegen
      • oder bestehende Standardnachrichtenklasse nutzen:
      • Nachrichtenklasse: 00
      • Nachrichtennummer: 398 (ergibt Nachrichtentext “& & & &”)
      • Nachrichtentext: wird automatisch aus der Nachrichtenklasse gezogen
      • Attrib. 1 zuweisen: T100_MSGV1
      • Attrib. 2 zuweisen: T100_MSGV2
      • Attrib. 3 zuweisen: T100_MSGV3
      • Attrib. 4 zuweisen: T100_MSGV4
    3. aktivieren

Auslösen der Exeption ZCX_MY_EXCEPTION

CLASS zxyz DEFINITION PUBLIC FINAL CREATE PUBLIC.

  PUBLIC SECTION.

    METHODS: constructor
      IMPORTING
        !iv_text TYPE string " Übergabestring für Test
      RAISING
        zcx_my_exception.    " Fehler im Konstruktor löst evtl. ZCX_MY_EXCEPTION aus

ENDCLASS.

CLASS zxyz IMPLEMENTATION.

  METHOD constructor.

    IF NOT iv_text IS INITIAL.

      ...
      
    ELSE.
* Text leer -> ZCX_MY_EXCEPTION auslösen
      RAISE EXCEPTION TYPE zcx_my_exception
        EXPORTING
          textid     = zcx_my_exception=>my_object_not_found
          t100_msgid = 'E'              " nicht verwendet
          t100_msgno = '000'            " nicht verwendet
          t100_msgv1 = 'Text war leer.' " 1. String, wenn benötigt
          t100_msgv2 = ''               " 2. String, wenn benötigt
          t100_msgv3 = ''               " 3. String, wenn benötigt
          t100_msgv4 = ''.              " 4. String, wenn benötigt
    ENDIF.
  ENDMETHOD.

ENDCLASS.

Exception ZCX_MY_EXCEPTION und abfangen und Text-ID MY_OBJECT_NOT_FOUND ausgeben

TRY.
* zum Auslösen der Exception ZCX_MY_EXCEPTION den Übergabeparameter leer lassen
    DATA(o_test) = NEW zxyz( iv_text = '' ).

* Exception abfangen
  CATCH cx_root INTO DATA(e_txt).
* Klassenname
    WRITE: / cl_abap_classdescr=>get_class_name( p_object = e_txt ).
* Messagetext
    WRITE: / e_txt->get_text( ).
ENDTRY.

Links

[ABAP] OO: Lokale Exception-Klasse anlegen, auslösen und behandeln

* lokale Exception-Klasse, erbt von cx_static_check
CLASS lcx_my_exception DEFINITION INHERITING FROM cx_static_check FINAL CREATE PUBLIC.
  PUBLIC SECTION.

* eigener Konstruktor mit zus. Parameter field_info
    METHODS: constructor
      IMPORTING
        !textid    LIKE textid OPTIONAL
        !previous  LIKE previous OPTIONAL
        field_info TYPE string OPTIONAL.

* neue Methode
    METHODS:
      get_fieldinfo
        RETURNING VALUE(re_field_info) TYPE string.

  PRIVATE SECTION.
    DATA: gv_field_info TYPE string.
ENDCLASS.

CLASS lcx_my_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor( textid = textid
                        previous = previous ).

    gv_field_info = field_info.
  ENDMETHOD.

  METHOD get_fieldinfo.
    re_field_info = gv_field_info.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_demo DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      div
        IMPORTING i_val1        TYPE f
                  i_val2        TYPE f
        RETURNING VALUE(rv_ret) TYPE f
* Propagieren der Exception
        RAISING   lcx_my_exception.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.
  METHOD div.
    IF i_val2 = '0.0'.
* Wenn durch 0.0 geteilt werden soll: Auslösen der lokalen Exception, zusätzlichen Parameter übergeben
      RAISE EXCEPTION TYPE lcx_my_exception
        EXPORTING
          field_info = 'Neue Feldinfo.'.
    ELSE.
      rv_ret = i_val1 / i_val2.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  TRY.
* durch 0.0 teilen -> Exception wird ausgelöst
      WRITE: / lcl_demo=>div( i_val1 = '1.1'
                              i_val2 = '0.0' ).
* Abfangen der lokalen Exception
    CATCH lcx_my_exception INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
* zusätzlichen Parameter holen
      WRITE: / e_txt->get_fieldinfo( ).
  ENDTRY.

[ABAP] OO: Instanzkonstruktor, funktionale Instanzmethode, Exceptionhandling

* Einfache Klasse für Demo des Konstruktors, Instanzmethode, Exceptionhandling
CLASS lcl_demo DEFINITION.
  PUBLIC SECTION.
* Instanzkonstruktor mit Übergabeparameter
* Propagiert Exception vom Typ cx_sy_create_object_error
    METHODS:
      constructor
        IMPORTING
          i_name TYPE string
        RAISING
          cx_sy_create_object_error.

* funktionale Instanzmethode, gibt Namen zurück
    METHODS:
      get_name RETURNING VALUE(rv_name) TYPE string.

  PRIVATE SECTION.
* globale, private Variable zur Speicherung des Namens
    DATA: gv_name TYPE string.
ENDCLASS.

CLASS lcl_demo IMPLEMENTATION.
  METHOD constructor.
* prüfen, ob Name leer
    IF i_name = ''.
* Exception werfen
      RAISE EXCEPTION TYPE cx_sy_create_object_error.
    ELSE.
      gv_name = i_name.
    ENDIF.
  ENDMETHOD.

  METHOD get_name.
* Namen zurückgeben
    rv_name = gv_name.
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
* Exception provozieren
  TRY.
      DATA(o_ref) = NEW lcl_demo( i_name = '' ).

      WRITE: / o_ref->get_name( ).

    CATCH cx_sy_create_object_error INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.
  
* "normale" Abarbeitung
  TRY.
      DATA(o_ref) = NEW lcl_demo( i_name = 'Test' ).

      WRITE: / o_ref->get_name( ).

    CATCH cx_sy_create_object_error INTO DATA(e_txt).
      WRITE: / e_txt->get_text( ).
  ENDTRY.

[ABAP] vordefinierte Ausnahmeklassen (Exception-Klassen) im System

Eine schöne Übersicht zu System-Exception-Klassen findet sich hier: Link

* häufig verwendete System-Ausnahmeklassen:

CX_ROOT
CX_SY_ARITHMETIC_ERROR
CX_SY_ZERODIVIDE
CX_SY_CREATE_OBJECT_ERROR
CX_SY_FILE_ACCESS_ERROR
CX_SY_ITAB_LINE_NOT_FOUND
CX_SY_SQL_ERROR

[ABAP] Exceptionhandling (obsolet)

Folgende Sprachelemente sollten nicht mehr angewendet werden, da sie mittlerweile obsolet sind:

Definition und Auslösen einer Exception

* Definition und Auslösen einer Exception
CLASS my_class DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS my_method
       IMPORTING var1 TYPE i
       EXCEPTIONS my_exception.
ENDCLASS.

* Auslösen einer Exception
CLASS my_class IMPLEMENTATION.
  METHOD my_method.
    ...
    RAISE my_exception.
    ...
  ENDMETHOD.
ENDCLASS.

Behandlung einer Exception

my_class=>my_method( EXPORTING var1 = 1
                     EXCEPTIONS my_exception = 1 ).
* Exception über sy-subrc abfragen
IF sy-subrc <> 0.
  MESSAGE 'Fehler.' TYPE 'I'.
ENDIF.

[ABAP] Objektorientiertes (OO) Exceptionhandling mit TRY … CATCH

Variante 1 (implizites Erzeugen von Objekten)

* DEMO_CATCH_EXCEPTION

START-OF-SELECTION.
  TRY.
      RAISE EXCEPTION TYPE cx_sy_zerodivide.
* Exception abfangen
    CATCH cx_sy_zerodivide INTO DATA(e_text).
      MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
  ENDTRY.

Variante 2 (explizites Erzeugen von Objekten)

START-OF-SELECTION.
  TRY.
      DATA(excp) = NEW cx_os_object_not_found( classname = 'MYCLASS' ).
      RAISE EXCEPTION excp.
* Exception abfangen
    CATCH cx_os_object_not_found INTO DATA(e_text).
      MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
  ENDTRY.

Variante 3 (explizites Erzeugen von Objekten – RE-RAISING)

START-OF-SELECTION.
  TRY.
      TRY.
          DATA(excp) = NEW cx_sy_file_open( filename = 'xyz.txt' ).
          RAISE EXCEPTION excp.
* Exception abfangen
        CATCH cx_root INTO DATA(exc).
* RE-RAISING einer neuen Exception
          RAISE EXCEPTION TYPE cx_sy_file_position
            EXPORTING
              previous = exc.
      ENDTRY.
* Exception abfangen
    CATCH cx_root INTO DATA(exc2).
      MESSAGE exc2->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
  ENDTRY.

Variante 4 (Runtime Exceptions)

START-OF-SELECTION.
  TRY.
* implizites Erzeugen von Exception cx_sy_zerodivide
      DATA(erg) = 1 / 0.
* Exception abfangen
    CATCH cx_root INTO DATA(e_text).
      MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
  ENDTRY.

Variante 5 (Beispiel – Definition und Auslösen einer OO-Exception)

CLASS my_class DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS: my_method
* Exception propagieren
      RAISING cx_sy_zerodivide.
ENDCLASS.
 
CLASS my_class IMPLEMENTATION.
  METHOD my_method.
    ...
* Auslösen der Systemexception cx_sy_zerodivide
    RAISE EXCEPTION TYPE cx_sy_zerodivide.
    ...
  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
* Behandlung einer OO-Exception
  TRY.
* Funktionsaufruf, der Exception cx_sy_zerodivide auslösen kann
      my_class=>my_method( ).
* Exception cx_sy_zerodivide abfangen
    CATCH cx_sy_zerodivide INTO DATA(e_text).
      MESSAGE e_text->get_text( ) TYPE 'S' DISPLAY LIKE 'E'.
  ENDTRY.

Weiterführende Information: Link und Link