Les classes d’exception permettent une gestion structurée des erreurs en ABAP. Les exceptions personnalisées (classes CX_) transportent les données d’erreur, supportent le multilinguisme et s’intègrent parfaitement avec TRY-CATCH.
Hiérarchie des exceptions
CX_ROOT │ ├── CX_STATIC_CHECK " Doit être déclarée (RAISING) │ └── CX_DYNAMIC_CHECK " Peut, mais n'a pas besoin d'être déclarée │ └── CX_NO_CHECK " N'a pas besoin d'être déclarée (Runtime)| Classe de base | RAISING nécessaire | Utilisation typique |
|---|---|---|
CX_STATIC_CHECK | Oui | Exceptions métier |
CX_DYNAMIC_CHECK | Optionnel | Erreurs techniques |
CX_NO_CHECK | Non | Erreurs système critiques |
Créer une classe d’exception
1. Exception simple (SE24/ADT)
CLASS zcx_validation_error DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. " Interface pour les textes INTERFACES: if_t100_message. INTERFACES: if_t100_dyn_msg.
" Constantes pour les textes de message CONSTANTS: BEGIN OF invalid_input, msgid TYPE symsgid VALUE 'ZMSG', msgno TYPE symsgno VALUE '001', attr1 TYPE scx_attrname VALUE 'MV_FIELD', attr2 TYPE scx_attrname VALUE '', attr3 TYPE scx_attrname VALUE '', attr4 TYPE scx_attrname VALUE '', END OF invalid_input.
" Attributs pour les données d'erreur DATA: mv_field TYPE string READ-ONLY.
" Constructeur METHODS: constructor IMPORTING textid LIKE if_t100_message=>t100key OPTIONAL previous LIKE previous OPTIONAL iv_field TYPE string OPTIONAL.
ENDCLASS.
CLASS zcx_validation_error IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ).
mv_field = iv_field.
CLEAR me->textid. IF textid IS INITIAL. if_t100_message~t100key = invalid_input. ELSE. if_t100_message~t100key = textid. ENDIF. ENDMETHOD.ENDCLASS.2. Exception avec plusieurs textes
CLASS zcx_order_error DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. INTERFACES: if_t100_message.
" Différents textes d'erreur CONSTANTS: BEGIN OF order_not_found, msgid TYPE symsgid VALUE 'ZORDER', msgno TYPE symsgno VALUE '001', attr1 TYPE scx_attrname VALUE 'MV_ORDER_ID', attr2 TYPE scx_attrname VALUE '', attr3 TYPE scx_attrname VALUE '', attr4 TYPE scx_attrname VALUE '', END OF order_not_found,
BEGIN OF order_already_shipped, msgid TYPE symsgid VALUE 'ZORDER', msgno TYPE symsgno VALUE '002', attr1 TYPE scx_attrname VALUE 'MV_ORDER_ID', attr2 TYPE scx_attrname VALUE 'MV_SHIP_DATE', attr3 TYPE scx_attrname VALUE '', attr4 TYPE scx_attrname VALUE '', END OF order_already_shipped,
BEGIN OF invalid_quantity, msgid TYPE symsgid VALUE 'ZORDER', msgno TYPE symsgno VALUE '003', attr1 TYPE scx_attrname VALUE 'MV_QUANTITY', attr2 TYPE scx_attrname VALUE 'MV_MAX_QUANTITY', attr3 TYPE scx_attrname VALUE '', attr4 TYPE scx_attrname VALUE '', END OF invalid_quantity.
" Attributs DATA: mv_order_id TYPE string READ-ONLY, mv_ship_date TYPE d READ-ONLY, mv_quantity TYPE i READ-ONLY, mv_max_quantity TYPE i READ-ONLY.
METHODS: constructor IMPORTING textid LIKE if_t100_message=>t100key OPTIONAL previous LIKE previous OPTIONAL iv_order_id TYPE string OPTIONAL iv_ship_date TYPE d OPTIONAL iv_quantity TYPE i OPTIONAL iv_max_quantity TYPE i OPTIONAL.
ENDCLASS.
CLASS zcx_order_error IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ).
mv_order_id = iv_order_id. mv_ship_date = iv_ship_date. mv_quantity = iv_quantity. mv_max_quantity = iv_max_quantity.
CLEAR me->textid. IF textid IS INITIAL. if_t100_message~t100key = order_not_found. ELSE. if_t100_message~t100key = textid. ENDIF. ENDMETHOD.ENDCLASS.3. Lever une exception (RAISE EXCEPTION)
CLASS lcl_order_service DEFINITION. PUBLIC SECTION. METHODS: get_order IMPORTING iv_order_id TYPE string RETURNING VALUE(rs_order) TYPE ty_order RAISING zcx_order_error.
METHODS: ship_order IMPORTING iv_order_id TYPE string RAISING zcx_order_error.ENDCLASS.
CLASS lcl_order_service IMPLEMENTATION. METHOD get_order. " Rechercher la commande SELECT SINGLE * FROM ztorders WHERE order_id = @iv_order_id INTO @rs_order.
IF sy-subrc <> 0. RAISE EXCEPTION TYPE zcx_order_error EXPORTING textid = zcx_order_error=>order_not_found iv_order_id = iv_order_id. ENDIF. ENDMETHOD.
METHOD ship_order. DATA: ls_order TYPE ty_order.
ls_order = get_order( iv_order_id ).
IF ls_order-status = 'SHIPPED'. RAISE EXCEPTION TYPE zcx_order_error EXPORTING textid = zcx_order_error=>order_already_shipped iv_order_id = iv_order_id iv_ship_date = ls_order-ship_date. ENDIF.
" Effectuer l'expédition... ENDMETHOD.ENDCLASS.4. Attraper et traiter une exception
DATA: lo_service TYPE REF TO lcl_order_service, ls_order TYPE ty_order.
lo_service = NEW #( ).
TRY. ls_order = lo_service->get_order( '12345' ).
CATCH zcx_order_error INTO DATA(lx_error). " Afficher le texte d'erreur DATA(lv_message) = lx_error->get_text( ). WRITE: / 'Erreur :', lv_message.
" Accéder aux attributs spécifiques WRITE: / 'ID Commande :', lx_error->mv_order_id.
" Relever l'erreur " RAISE EXCEPTION lx_error.ENDTRY.5. Chaîne d’exceptions (PREVIOUS)
METHOD process_order. TRY. " Opération base de données validate_order( is_order ).
CATCH zcx_validation_error INTO DATA(lx_val). " Passer l'exception originale comme PREVIOUS RAISE EXCEPTION TYPE zcx_order_error EXPORTING textid = zcx_order_error=>order_not_found previous = lx_val iv_order_id = is_order-id. ENDTRY.ENDMETHOD.
" Lors de la capture : parcourir la chaîneTRY. process_order( ls_order ).
CATCH cx_root INTO DATA(lx_error). " Afficher toutes les exceptions de la chaîne DATA(lx_current) = lx_error.
WHILE lx_current IS BOUND. WRITE: / lx_current->get_text( ). lx_current = lx_current->previous. ENDWHILE.ENDTRY.6. Exception sans classe de message
CLASS zcx_simple_error DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. " Texte simple sans T100 DATA: mv_message TYPE string READ-ONLY.
METHODS: constructor IMPORTING iv_message TYPE string OPTIONAL previous LIKE previous OPTIONAL.
METHODS: if_message~get_text REDEFINITION.
ENDCLASS.
CLASS zcx_simple_error IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ). mv_message = iv_message. ENDMETHOD.
METHOD if_message~get_text. result = mv_message. ENDMETHOD.ENDCLASS.
" UtilisationRAISE EXCEPTION TYPE zcx_simple_error EXPORTING iv_message = 'Une erreur s''est produite'.7. COND/SWITCH avec THROW
DATA: lv_age TYPE i VALUE -5.
" Lever une exception dans une expressionDATA(lv_status) = COND string( WHEN lv_age >= 0 AND lv_age < 18 THEN 'Mineur" WHEN lv_age >= 18 THEN 'Adulte" ELSE THROW zcx_validation_error( textid = zcx_validation_error=>invalid_input iv_field = 'AGE" )).
" Avec SWITCHDATA(lv_result) = SWITCH string( lv_status WHEN 'A' THEN 'Actif" WHEN 'I' THEN 'Inactif" ELSE THROW zcx_validation_error( iv_field = 'STATUS' )).8. Classe d’exception locale
" Pour tests ou utilisation localeCLASS lcx_local_error DEFINITION INHERITING FROM cx_static_check.
PUBLIC SECTION. DATA: mv_info TYPE string READ-ONLY.
METHODS: constructor IMPORTING iv_info TYPE string OPTIONAL previous LIKE previous OPTIONAL.
METHODS: if_message~get_text REDEFINITION.ENDCLASS.
CLASS lcx_local_error IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ). mv_info = iv_info. ENDMETHOD.
METHOD if_message~get_text. result = |Erreur locale : { mv_info }|. ENDMETHOD.ENDCLASS.9. Hiérarchie d’exceptions pour un domaine
" Classe de base pour toutes les exceptions OrderCLASS zcx_order_base DEFINITION PUBLIC ABSTRACT INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. DATA: mv_order_id TYPE string READ-ONLY.
METHODS: constructor IMPORTING iv_order_id TYPE string OPTIONAL previous LIKE previous OPTIONAL.ENDCLASS.
" Exceptions spécifiquesCLASS zcx_order_not_found DEFINITION PUBLIC INHERITING FROM zcx_order_base CREATE PUBLIC. " ...ENDCLASS.
CLASS zcx_order_locked DEFINITION PUBLIC INHERITING FROM zcx_order_base CREATE PUBLIC. " ...ENDCLASS.
CLASS zcx_order_invalid_state DEFINITION PUBLIC INHERITING FROM zcx_order_base CREATE PUBLIC. " ...ENDCLASS.
" Attraper selon la hiérarchieTRY. process_order( ).
CATCH zcx_order_not_found INTO DATA(lx_not_found). " Traitement spécifique
CATCH zcx_order_locked INTO DATA(lx_locked). " Traitement spécifique
CATCH zcx_order_base INTO DATA(lx_order). " Toutes les autres exceptions Order
CATCH cx_static_check INTO DATA(lx_other). " Toutes les autres exceptions statiques
ENDTRY.10. Intégration MESSAGE
" Classe de messages ZMSG avec message 001 :" "Le champ & contient une valeur invalide"
CLASS zcx_with_message DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. INTERFACES: if_t100_message. INTERFACES: if_t100_dyn_msg.
CONSTANTS: BEGIN OF field_invalid, msgid TYPE symsgid VALUE 'ZMSG', msgno TYPE symsgno VALUE '001', attr1 TYPE scx_attrname VALUE 'MV_FIELD', attr2 TYPE scx_attrname VALUE '', attr3 TYPE scx_attrname VALUE '', attr4 TYPE scx_attrname VALUE '', END OF field_invalid.
DATA: mv_field TYPE string READ-ONLY.
METHODS: constructor IMPORTING textid LIKE if_t100_message=>t100key OPTIONAL previous LIKE previous OPTIONAL iv_field TYPE string OPTIONAL.
ENDCLASS.
" Lever l'exceptionRAISE EXCEPTION TYPE zcx_with_message EXPORTING textid = zcx_with_message=>field_invalid iv_field = 'KUNNR'.
" Récupérer le texteCATCH zcx_with_message INTO DATA(lx_error). " get_text() retourne : "Le champ KUNNR contient une valeur invalide" DATA(lv_msg) = lx_error->get_text( ).
" Ou comme MESSAGE MESSAGE lx_error TYPE 'I'.11. Exceptions RESUMABLE
CLASS zcx_resumable_error DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. DATA: mv_value TYPE i READ-ONLY.
METHODS: constructor IMPORTING iv_value TYPE i OPTIONAL previous LIKE previous OPTIONAL.ENDCLASS.
METHOD process_values. LOOP AT lt_values INTO DATA(lv_value). IF lv_value < 0. " RESUMABLE : Peut être continué avec RESUME RAISE RESUMABLE EXCEPTION TYPE zcx_resumable_error EXPORTING iv_value = lv_value. ENDIF.
" Traitement suivant... ENDLOOP.ENDMETHOD.
" Appel avec RESUMETRY. process_values( ).
CATCH BEFORE UNWIND zcx_resumable_error INTO DATA(lx_error). WRITE: / 'Avertissement : Valeur négative', lx_error->mv_value. RESUME. " Continuer après RAISE RESUMABLEENDTRY.12. Bonne pratique : Factory d’exception
CLASS zcx_factory DEFINITION. PUBLIC SECTION. CLASS-METHODS: not_found IMPORTING iv_entity TYPE string iv_id TYPE string RETURNING VALUE(ro_exception) TYPE REF TO zcx_not_found,
validation_failed IMPORTING iv_field TYPE string iv_message TYPE string RETURNING VALUE(ro_exception) TYPE REF TO zcx_validation_error.ENDCLASS.
CLASS zcx_factory IMPLEMENTATION. METHOD not_found. ro_exception = NEW #( iv_entity = iv_entity iv_id = iv_id ). ENDMETHOD.
METHOD validation_failed. ro_exception = NEW #( iv_field = iv_field iv_message = iv_message ). ENDMETHOD.ENDCLASS.
" UtilisationRAISE EXCEPTION zcx_factory=>not_found( iv_entity = 'Customer" iv_id = '12345").Créer une classe d’exception dans SE24
- SE24 → Créer une classe (le nom commence par
ZCX_ouYCX_) - Superclasse :
CX_STATIC_CHECK(ou autre) - Interfaces : Ajouter
IF_T100_MESSAGE - Attributs : Définir les données d’erreur (par ex.
MV_ORDER_ID) - Textes : Lier les IDs d’exception avec la classe de messages
- Constructeur : Définir les paramètres pour les attributs
Remarques importantes / Bonnes pratiques
- CX_STATIC_CHECK pour les exceptions métier (doivent être déclarées dans RAISING).
- Propre hiérarchie pour les domaines fonctionnels (par ex.
ZCX_ORDER_BASE). - IF_T100_MESSAGE pour les textes multilingues avec classe de messages.
- PREVIOUS pour les chaînes d’exceptions (tracer la cause).
- READ-ONLY pour les attributs d’exception (immutabilité).
- Attrapez les exceptions spécifiques d’abord, puis les plus générales.
- THROW dans
COND/SWITCHpour les exceptions inline. - RESUMABLE pour les avertissements qui peuvent être ignorés.
- Textes d’exception dans la classe de messages pour la traductibilité.
- get_text() pour le message d’erreur formaté.