Las Clases de Excepcion son el mecanismo moderno de manejo de errores en ABAP. Reemplazan a los codigos de retorno clasicos y permiten manejo de errores estructurado con TRY-CATCH.
Jerarquia de Excepciones
CX_ROOT (Abstracta)├── CX_STATIC_CHECK - Debe declararse o capturarse├── CX_DYNAMIC_CHECK - Se verifica en tiempo de ejecucion└── CX_NO_CHECK - No requiere declaracion| Tipo | Cuando usar |
|---|---|
CX_STATIC_CHECK | Errores esperados que el llamador debe manejar |
CX_DYNAMIC_CHECK | Errores de programacion (indice fuera de rango) |
CX_NO_CHECK | Errores del sistema, raramente manejables |
Sintaxis basica
TRY-CATCH
TRY. " Codigo que puede lanzar excepcion lo_object->do_something( ).
CATCH cx_some_exception INTO DATA(lx_error). " Manejar el error DATA(lv_message) = lx_error->get_text( ).
CLEANUP. " Siempre se ejecuta si hay excepcion no capturada " Limpiar recursosENDTRY.Ejemplos
1. Crear clase de excepcion simple
CLASS zcx_order_error DEFINITION PUBLIC INHERITING FROM cx_static_check FINAL CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_t100_message.
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.
DATA: mv_order_id TYPE string READ-ONLY.
METHODS constructor IMPORTING textid LIKE if_t100_message=>t100key OPTIONAL previous LIKE previous OPTIONAL order_id TYPE string OPTIONAL.
ENDCLASS.
CLASS zcx_order_error IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ).
mv_order_id = order_id.
CLEAR me->textid. IF textid IS INITIAL. if_t100_message~t100key = if_t100_message=>default_textid. ELSE. if_t100_message~t100key = textid. ENDIF. ENDMETHOD.ENDCLASS.2. Lanzar excepcion
METHOD get_order. SELECT SINGLE * FROM zorders 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 order_id = iv_order_id. ENDIF.ENDMETHOD.3. Capturar excepcion
TRY. DATA(ls_order) = lo_service->get_order( '12345' ). WRITE: / 'Pedido encontrado:', ls_order-order_id.
CATCH zcx_order_error INTO DATA(lx_error). WRITE: / 'Error:', lx_error->get_text( ). WRITE: / 'ID del pedido:', lx_error->mv_order_id.ENDTRY.4. Multiples tipos de excepcion
TRY. lo_service->process_order( iv_order_id ).
CATCH zcx_order_not_found INTO DATA(lx_not_found). " Manejar pedido no encontrado WRITE: / 'Pedido no existe:', lx_not_found->mv_order_id.
CATCH zcx_order_locked INTO DATA(lx_locked). " Manejar pedido bloqueado WRITE: / 'Pedido bloqueado por:', lx_locked->mv_locked_by.
CATCH zcx_order_error INTO DATA(lx_general). " Manejar otros errores de pedido WRITE: / 'Error general:', lx_general->get_text( ).
CATCH cx_root INTO DATA(lx_any). " Capturar cualquier otra excepcion WRITE: / 'Error inesperado:', lx_any->get_text( ).ENDTRY.5. CLEANUP para limpieza
DATA: lo_file TYPE REF TO zcl_file_handler.
TRY. CREATE OBJECT lo_file. lo_file->open( 'data.txt' ). lo_file->process( ). lo_file->close( ).
CATCH zcx_file_error INTO DATA(lx_error). WRITE: / 'Error de archivo:', lx_error->get_text( ).
CLEANUP. " Se ejecuta si la excepcion no se captura aqui " y se propaga hacia arriba IF lo_file IS BOUND. lo_file->close( ). ENDIF.ENDTRY.6. Relanzar excepcion
METHOD process_with_logging. TRY. lo_service->do_something( ).
CATCH zcx_service_error INTO DATA(lx_error). " Loguear antes de relanzar log_error( lx_error ).
" Relanzar la misma excepcion RAISE EXCEPTION lx_error.
" O envolver en otra excepcion* RAISE EXCEPTION TYPE zcx_wrapper_error* EXPORTING previous = lx_error. ENDTRY.ENDMETHOD.7. Excepcion con mensaje T100
CLASS zcx_validation_error DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_t100_message. INTERFACES if_t100_dyn_msg.
CONSTANTS: BEGIN OF field_required, msgid TYPE symsgid VALUE 'ZVAL', msgno TYPE symsgno VALUE '001', attr1 TYPE scx_attrname VALUE 'MV_FIELD_NAME', attr2 TYPE scx_attrname VALUE '', attr3 TYPE scx_attrname VALUE '', attr4 TYPE scx_attrname VALUE '', END OF field_required,
BEGIN OF value_invalid, msgid TYPE symsgid VALUE 'ZVAL', msgno TYPE symsgno VALUE '002', attr1 TYPE scx_attrname VALUE 'MV_FIELD_NAME', attr2 TYPE scx_attrname VALUE 'MV_VALUE', attr3 TYPE scx_attrname VALUE '', attr4 TYPE scx_attrname VALUE '', END OF value_invalid.
DATA: mv_field_name TYPE string READ-ONLY, mv_value TYPE string READ-ONLY.
METHODS constructor IMPORTING textid LIKE if_t100_message=>t100key OPTIONAL previous LIKE previous OPTIONAL field_name TYPE string OPTIONAL value TYPE string OPTIONAL.ENDCLASS.8. Encadenamiento de excepciones (previous)
METHOD outer_method. TRY. inner_method( ).
CATCH zcx_inner_error INTO DATA(lx_inner). " Envolver excepcion interna RAISE EXCEPTION TYPE zcx_outer_error EXPORTING textid = zcx_outer_error=>processing_failed previous = lx_inner. ENDTRY.ENDMETHOD.
" Al capturar, se puede acceder a la cadenaTRY. outer_method( ).
CATCH zcx_outer_error INTO DATA(lx_error). WRITE: / 'Error externo:', lx_error->get_text( ).
" Acceder a excepcion original DATA(lx_previous) = lx_error->previous. IF lx_previous IS BOUND. WRITE: / 'Causa:', lx_previous->get_text( ). ENDIF.ENDTRY.9. RAISE EXCEPTION vs. RAISE SHORTDUMP
" Excepcion manejableRAISE EXCEPTION TYPE zcx_business_error.
" Shortdump inmediato (solo para errores criticos)RAISE SHORTDUMP TYPE cx_sy_program_error EXPORTING reason = 'Inconsistencia de datos detectada'.10. Declarar excepciones en firma de metodo
CLASS zcl_order_service DEFINITION. PUBLIC SECTION. METHODS: " CX_STATIC_CHECK debe declararse get_order IMPORTING iv_id TYPE string RETURNING VALUE(rs_order) TYPE ty_order RAISING zcx_order_not_found zcx_order_locked,
" CX_DYNAMIC_CHECK no necesita declararse pero puede calculate IMPORTING iv_value TYPE i RETURNING VALUE(rv_result) TYPE i, " RAISING zcx_division_by_zero <- opcional
" CX_NO_CHECK nunca se declara process IMPORTING iv_data TYPE string.ENDCLASS.11. COND/SWITCH con excepciones
" COND con THROWDATA(lv_status_text) = COND string( WHEN lv_status = 'A' THEN 'Activo' WHEN lv_status = 'I' THEN 'Inactivo' ELSE THROW zcx_invalid_status( status = lv_status )).
" SWITCH con THROWDATA(lv_priority) = SWITCH i( lv_code WHEN 'H' THEN 1 WHEN 'M' THEN 2 WHEN 'L' THEN 3 ELSE THROW zcx_unknown_code( )).12. Excepcion en expresion de tabla
" Lanza CX_SY_ITAB_LINE_NOT_FOUND si no existeTRY. DATA(ls_item) = it_items[ id = '123' ].
CATCH cx_sy_itab_line_not_found. WRITE: / 'Item no encontrado'.ENDTRY.
" Alternativa: DEFAULT para evitar excepcionDATA(ls_item2) = VALUE #( it_items[ id = '123' ] DEFAULT ls_empty ).13. Clase de excepcion con metodos auxiliares
CLASS zcx_validation DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. INTERFACES if_t100_message.
DATA: mt_errors TYPE string_table READ-ONLY.
METHODS: constructor IMPORTING textid LIKE if_t100_message=>t100key OPTIONAL previous LIKE previous OPTIONAL errors TYPE string_table OPTIONAL,
get_error_count RETURNING VALUE(rv_count) TYPE i,
get_all_messages RETURNING VALUE(rt_messages) TYPE string_table.ENDCLASS.
CLASS zcx_validation IMPLEMENTATION. METHOD constructor. super->constructor( previous = previous ). mt_errors = errors.
IF textid IS INITIAL. if_t100_message~t100key = if_t100_message=>default_textid. ELSE. if_t100_message~t100key = textid. ENDIF. ENDMETHOD.
METHOD get_error_count. rv_count = lines( mt_errors ). ENDMETHOD.
METHOD get_all_messages. rt_messages = mt_errors. ENDMETHOD.ENDCLASS.14. Pattern: Result Type (alternativa a excepciones)
" Clase de resultadoCLASS zcl_result DEFINITION. PUBLIC SECTION. DATA: is_success TYPE abap_bool READ-ONLY, value TYPE REF TO data READ-ONLY, error TYPE REF TO cx_root READ-ONLY.
CLASS-METHODS: success IMPORTING iv_value TYPE any RETURNING VALUE(ro_result) TYPE REF TO zcl_result, failure IMPORTING ix_error TYPE REF TO cx_root RETURNING VALUE(ro_result) TYPE REF TO zcl_result.
METHODS get_value_or_throw RETURNING VALUE(rv_value) TYPE any RAISING cx_root.ENDCLASS.
" UsoDATA(lo_result) = lo_service->find_customer( '123' ).
IF lo_result->is_success. DATA(ls_customer) = lo_result->value->*.ELSE. WRITE: / 'Error:', lo_result->error->get_text( ).ENDIF.15. Resumable Exceptions
CLASS zcx_resumable DEFINITION PUBLIC INHERITING FROM cx_static_check CREATE PUBLIC.
PUBLIC SECTION. " Marcar como resumible INTERFACES if_t100_message.ENDCLASS.
" Lanzar como resumibleMETHOD process. TRY. RAISE RESUMABLE EXCEPTION TYPE zcx_resumable.
CATCH BEFORE UNWIND zcx_resumable INTO DATA(lx_res). " Decidir si continuar IF can_continue( ). RESUME. " Continuar despues del RAISE ELSE. RAISE EXCEPTION lx_res. " Propagar ENDIF. ENDTRY.ENDMETHOD.Resumen
| Elemento | Descripcion |
|---|---|
CX_STATIC_CHECK | Debe declararse/capturarse |
CX_DYNAMIC_CHECK | Verificacion en runtime |
CX_NO_CHECK | Sin verificacion |
RAISE EXCEPTION TYPE | Lanzar excepcion |
CATCH ... INTO | Capturar excepcion |
CLEANUP | Limpieza antes de propagar |
previous | Encadenar excepciones |
Notas importantes / Mejores practicas
- Heredar de
CX_STATIC_CHECKpara errores de negocio esperados. - Usar mensajes T100 para textos traducibles.
- Capturar excepciones lo mas especifico posible.
- Usar
previouspara mantener la cadena de errores. CLEANUPsolo se ejecuta si la excepcion no se captura localmente.- No usar excepciones para control de flujo normal.
- Preferir nombres descriptivos:
ZCX_ORDER_NOT_FOUNDvsZCX_ERROR. - En RAP: usar las estructuras
FAILEDyREPORTEDen lugar de excepciones.