Classes d

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

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 baseRAISING nécessaireUtilisation typique
CX_STATIC_CHECKOuiExceptions métier
CX_DYNAMIC_CHECKOptionnelErreurs techniques
CX_NO_CHECKNonErreurs 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îne
TRY.
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.
" Utilisation
RAISE 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 expression
DATA(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 SWITCH
DATA(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 locale
CLASS 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 Order
CLASS 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écifiques
CLASS 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érarchie
TRY.
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'exception
RAISE EXCEPTION TYPE zcx_with_message
EXPORTING
textid = zcx_with_message=>field_invalid
iv_field = 'KUNNR'.
" Récupérer le texte
CATCH 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 RESUME
TRY.
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 RESUMABLE
ENDTRY.

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.
" Utilisation
RAISE EXCEPTION zcx_factory=>not_found(
iv_entity = 'Customer"
iv_id = '12345"
).

Créer une classe d’exception dans SE24

  1. SE24 → Créer une classe (le nom commence par ZCX_ ou YCX_)
  2. Superclasse : CX_STATIC_CHECK (ou autre)
  3. Interfaces : Ajouter IF_T100_MESSAGE
  4. Attributs : Définir les données d’erreur (par ex. MV_ORDER_ID)
  5. Textes : Lier les IDs d’exception avec la classe de messages
  6. 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/SWITCH pour 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é.