Klassenbasierte Ausnahmen (TRY - CATCH - ENDTRY)

Aus SAP-Wiki
(Weitergeleitet von Klassenbasierte Ausnahmen)
Wechseln zu: Navigation, Suche

Siehe Fehlerbehandlung.

Mit dem Befehl "TRY - CATCH - ENDTRY" lassen sich sehr komfortabel klassenbasierte Ausnahmen abfangen, die durch SAP während der Laufzeit im gleichen Programm oder aufgerufenen Programmen ausgelöst wurden. Der Meldungstext wird durch die Ausnahmeklasse geliefert. Man muss nicht mehr wissen von welchem Programm in der Aufrufhierarchie die Ausnahme ausgelöst wurde.

Mit "txterror = oerror->get_text( )" wird der Fehler in die String-Variable TXTERROR geschrieben und kann dann z B in einer Meldung ausgegeben werden, in einem Write-Bildschirm oder ins Application Log. Hier ist der Text auf 50 Zeichen beschränkt. Längerer Text wird mit "lv_txterror_long = oerror->get_longtext ( )" ausgelesen und in die Variable "LV_TXTERROR" geschrieben. Sowohl "TXTERROR" als auch "LV_TXTERROR" haben den Datentyp String.

Globale Ausnahmeklassen werden in der Transaktion SE24 (Class Builder) definiert und verwaltet. Alle Ausnahmeklassen sind Erben der gemeinsamen Oberklasse CX_ROOT oder einer ihrer Unterklassen. Meist müssen aber keine eigenen Ausnahmeklassen definiert werden, sondern es können die vorhandenen SAP-Ausnahmeklassen verwendet werden.

Codingvorlage

 DATA: oerror TYPE REF TO cx_root,               "Abstrakte Oberklasse aller globalen Exceptions (s. Anzeige Klasse CX_ROOT in SE80)
       lv_txterror TYPE string,
       lv_txterror_long type string.

 TRY.
     data(lv_zahl) = 4 / 0.                      "auslösendes Ereignis

   CATCH cx_sy_zerodivide INTO oerror.
     lv_txterror_long = oerror->get_longtext( ). "Langtext kann über 50 Zeichen sein

     message lv_txterror_long type 'I'.          "Auch Texte über 50 Zeichen werden ausgegeben
                                                 "A", "E", "I", "S" oder "W" in Großbuchstaben
 ENDTRY.

TRY - ENDTRY

  • Mit "TRY. ... ENDTRY." wird der Codingbereich umschlossen, bei dem ein Fehler auftreten kann.
  • Der Catch-Bereich behandelt den Fehler. Er ist im Try-Block eingeschlossen.
try.
 ...     "möglicher Fehlerauslöser
 catch <fehlerklasse>.  "Abfangen des Fehlers
   ...                  "Behandlung des Fehlers
endtry.

Catch

  • Mit "CATCH <ausnahmeklasse> wird eine bestimmte Ausnahme behandelt. Wenn in TRY-ENDTRY-Bereich diese Ausnahme ausgelöst wird, wird sofort der CATCH-Block angesprungen.
  • Wenn eine andere Ausnahme ausgelöst wird, die nicht im CATCH-Block definiert ist, bricht das Programm mit einem Laufzeitfehler ab.
  • Es können in einem CATCH-Befehle auch mehrere mögliche Ausnahmen abgefangen werden, wie hier beim Funktionsbaustein "FP_FUNCTION_MODULE_NAME".


Im Funktionsbaustein "FP_FUNCTION_MODULE_NAME" sieht man, dass hier 3 verschiedene Ausnahmen ausgelöst werden können.

Catch1.JPG


Die 3 Ausnahmen werden nun direkt nach dem CATCH-Befehl aufgeführt.

 TRY.
     CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'
       EXPORTING
         i_name     = p_form
       IMPORTING
         e_funcname = lv_fm_name.

   CATCH cx_fp_api_repository
         cx_fp_api_usage
         cx_fp_api_internal.
   ...

 ENDTRY.

Ausnahmeklasse CX_ROOT

Alle Ausnahmeklassen leiten sich von der abstrakten Ausnahmeklasse CX_ROOT ab. Unter der Rootklasse CX_ROOT gibt es die abgeleiteten abstrakten Klassen

  • CX_DYNAMIC_CHECK
  • CX_NO_CHECK
  • CX_STATIC_CHECK.

Unter diesen Klassen gibt es weitere Klassen. In der Transaktion SE80 lässt sich diese Hierarchie anzeigen.

Ausnahmeklasse3.jpg


Bei der Ausnahmeklasse CX_DEMO_CONSTRUCTOR sieht man auch den Verberbungsbaum zur abstrakten Oberklasse CX_STATIC_CHECK und diese zur Klasse CX_ROOT.

KlassenbasAusnahme13.jpg


Ein anderes Beispiel von der Klasse CX_ZERODIVIDE zur Superklasse CX_ROOT.

KlassenbasAusnahme15.JPG

Identifikation Ausnahmeklasse

Es ist einfach die passende Ausnahmeklasse zu finden, wenn das Programm mit einem Laufzeitfehler (Shortdump) abbricht.

Wenn z. B. eine Division durch Null außerhalb eines Try-Catch-Endtry gemacht wird, wird ein Laufzeitfehler ausgelöst.

Data: lv_zahl type i.

lv_zahl = 4 / 0.

Im Text wird auf die Ausnahmeklasse CX_SY_ZERODIVIDE hingewiesen. Die kann nun verwendet werden.

Ausnahmeklasse6.JPG


bzw. hier bei einem anderen Fall im Langtext

Ausnahmeklasse1.jpg




Die Hierarchie zur obersten abstrakten Ausnahmeklasse CX_ROOT.

Ausnahmeklasse4.jpg


Eine Catch-Anweisung auf CX_SY_ZERODIVE behandelt nun die Ausnahme.

DATA: oerror           TYPE REF TO cx_root,
      lv_txterror      TYPE string,
      lv_txterror_long type string.

Data: lv_zahl type i.

TRY.
    lv_zahl = 4 / 0.

* Die Ausnahmeklasse CX_SY_ZERODIVIDE wird nun ausgelöst
* Das Objekt "oerror" beeinhaltet nun die Fehlerinformation
  CATCH CX_SY_ZERODIVIDE INTO oerror.
    lv_txterror      = oerror->get_text( ).      "Zuweisung Fehlertext der Ausnahmeklasse

*   Der Langtext wird in den String geschrieben (oft über 50 Zeichen)
    lv_txterror_long = oerror->get_longtext ( ). 
    MESSAGE i531(0u) WITH txterror.
ENDTRY.


Nun gibt es keinen Shortdump mehr, sondern eine aussagekräftige Meldung.

Ausnahmeklasse2.jpg

Ausnahmen in Aufrufhierarchie

Klassenbasierte Ausnahmen müssen nicht in dem Programm behandelt werden, in dem sie ausgelöst werden. Das hat den großen Vorteil, dass die klassenbasierten Ausnahmen durchgereicht werden können entlang der Aufrufhistorie und von einem übergeordneten Programm behandelt werden können.

HIer wird eine Ausnahme der Ausnahmeklasse CX_DEMO_CONSTRUCTOR ausgelöst mit dem Befehl

RAISE EXCEPTION TYPE <ausnahmeklasse>.

KlassenbasAusnahme2.jpg


Die klassenbasierte Ausnahme muss hier in in der Methode CX unter den Ausnahmen eingetragen sein.

KlassenbasAusnahme8.jpg


Wichtig ist die Checkbox KlassenbasAusnahme9.jpg, die der Methode sagt, dass hier eine klassenbasierte Ausnahme vorliegt. Man muss sich entscheiden innerhalb einer Methode zwischen klassenbasierten Ausnahmen und klassischen Ausnahmen.


Der aufrufende Report ZREBCX kann nun die klassenbasierte Ausnahme der Methode CX der Klasse ZREBERROR behandeln.

KlassenbasAusnahme6.jpg


Bei Funktionsbausteinen gibt es im Reiter "Ausnahmen" die gleiche Checkbox "Ausnameklassen", die für die Erzeugung einer klassenbasierten Ausnahme benötigt wird. Hier beim Funktionsbausetin FP_JOB_OPEN gibt es. nur klassischen Ausnahmen.

KlassenbasAusnahme10.jpg

Beispielcoding Division durch Null

Hier beim nachfolgenden Beispiel bei einer Division durch Null kann es passieren, dass ein Laufzeitfehler entsteht. Damit das Programm nicht mit einem Laufzeitfehler abbricht, wird eine Try-Endtry-Routine eingesetzt.

Das meiste Coding kann im Try-Catch-Endtry bei jedem Fehler gleich verwendet werden und insofern kann man das Coding zunächst gut mit einer Vorlage wie dieser einfügen und dann nur das Coding mit dem fehlerauslösenden Ereignis austauschen.

Die Fehlerklasse, in diesem Fall "CX_SY_ZERODIVIDE" sieht man im Text des Laufzeitfehlrs, wenn einmal der Shortdump nicht durch den Try-Catch-Endtry abgefangen wurde.

  DATA: oerror TYPE REF TO cx_root,  "Abstrakte Oberklasse aller globalen Exceptions (s. Anzeige Klasse CX_ROOT in SE80)
        lv_txterror TYPE string,
        lv_txterror_long type string.

  DATA: lv_zahl TYPE i.

  TRY.
      lv_zahl = 4 / 0.

    CATCH cx_sy_zerodivide INTO oerror.
      lv_txterror = oerror->get_text( ).
      lv_txterror_long = oerror->get_longtext( ). "Langtext ist oft über 50 Zeichen

     "MESSAGE i531(0u) WITH lv_txterror.

      message lv_txterror_long type 'I'.          "Auch Texte über 50 Zeichen werden ausgegeben

  ENDTRY.

Beispielcoding Dynamische Programmierung

Beim nachfolgenden Beispiel mit einer dynamischen Programmierung kann es passieren, dass Selektionsfelder übergeben oder Where-Felder abgefragt werden, die nicht existieren. Da diese Felder erst zur Laufzeit bekannt sind, kann die Syntaxprüfung diese Fehler nicht vorher abfangen.

Die Ausnahmeklasse CX_SY_DYNAMIC_OSQL_SEMANTICS löst im Fehlerfall eine Ausnahme aus, die dann behandelt werden kann.

DATA: oerror TYPE REF TO cx_root,
      txterror TYPE string.

 TRY.
     SELECT (gt_adressenfelder)
       INTO TABLE p_ct_itab
       FROM ztest
       WHERE (gt_where).

   CATCH cx_sy_dynamic_osql_semantics INTO oerror.
     txterror = oerror->get_text( ).
     MESSAGE i531(0u) WITH txterror.
 ENDTRY.

Constructor Ausnahmeklasse

Jede SAP-Ausnahmeklasse hat eine Constructor-Methode.

KlassenbasAusnahme11.jpg


KlassenbasAusnahme12.jpg


Hier wird der Constructor der Ausnahmeklasse CX_DEMO_CONSTRUCTOR mit einem Parameter MY_TEXT aufgerufen und SY-REPID übergeben.

KlassenbasAusnahme2.jpg


Das aktuelle Programm ist letztlich ein Bestandteil der Fehlerbeschreibung.

KlassenbasAusnahme7.jpg

Try- und Catch-Behandlung in einem Programm

  • Die Ausnahme wird in der Laufzeitumgebung von SAP ausgelöst oder über den Befehl "Raise Exception" im SAP-Programm.
REPORT demo_raise_exceptions.
DATA oref TYPE REF TO cx_root.
DATA text TYPE string.

TRY.
    RAISE EXCEPTION TYPE cx_demo_constructor
      EXPORTING
        my_text = sy-repid.
    CATCH cx_demo_constructor INTO oref.
      text = oref->get_text( ).
      WRITE / text.
ENDTRY.

Laufzeitfehler

  • Wirft ein Programm eine klassenbasierte Ausnahme mit "raise exception", dann muss dieses Programm oder ein anderes Programm in der Aufrufhierarchie diese Ausnahme behandeln. Erfolgt dies nicht, kommt es zu einem Laufzeitfehler
  • Hier ruft ein Report eine Methode CX der Klasse ZREBERROR auf, in der die klassenbasierte Ausnahme ausgelöst wird. Zur Provokation des Laufzeitfehlers wurde hier innerhalb des Try-Blocks der Catch auskommentiert.

KlassenbasAusnahme1.jpg


KlassenbasAusnahme2.jpg


KlassenbasAusnahme3.jpg


Mit dem Button KlassenbasAusnahme5.jpg kommt man zu einer ausführlicheren Beschreibung der Ausnahme.

KlassenbasAusnahme4.jpg


Sobald die Catch-Behandlung wieder aktiv ist, wird auch kein Laufzeitfehler mehr ausgelöst.

KlassenbasAusnahme6.jpg


KlassenbasAusnahme7.jpg

Web-Links

Literatur