Analizar y probar el código
Uso correcto de tipos de datos y conversiones de tipos
Campos de caracteres de procesamiento
Uso de la transferencia de código en ABAP SQL
Mejora del rendimiento de la tabla interna
Implementar verificaciones de autorización
Diseño de código orientado a objetos efectivo
Definir y trabajar con clases de excepción
Añadir documentación al código ABAP

Trabajar con clases de excepción

Objective

After completing this lesson, you will be able to trabajar con clases de excepción.

Tratamiento de excepciones

Anteriormente en este curso, observamos el tratamiento de errores mediante las sentencias TRY, CATCH y ENDTRY. Después de la sentencia TRY aparece la sentencia que puede causar un error. Si se produce el error, el sistema pasará a la sentencia CATCH y procesará su contenido. Independientemente de lo que ocurra, el método continúa el procesamiento después de la sentencia ENDTRY.

En un bloque TRY…ENDTRY, puede incluir más de una sentencia CATCH. Esto le permite tratar diferentes excepciones de forma diferente.

Puede enumerar varias excepciones en una única sentencia CATCH. En este ejemplo, se procesará el mismo bloque CATCH si el sistema desencadena cx_sy_arithmetic_error o cx_sy_zerodivide.

Cuando enumera una clase en una sentencia CATCH, el sistema procesará el bloque correspondiente si se desencadena una excepción con esa clase o una de sus subclases. En este ejemplo, cx_sy_arithmetic_error es una clase superior de cx_sy_arithmetic_overflow y cx_sy_zerodivide. Consecuentemente, el bloque se procesará si se genera una excepción con el tipo de cualquiera de las subclases.

Todas las clases de excepción forman parte de una jerarquía de herencia cuya clase superior superior es la clase cx_root. Como ya hemos visto, si utiliza una clase superior en una sentencia CATCH, el sistema saltará a ella si se desencadena una excepción con el tipo de cualquiera de sus subclases. Dado que todas las clases de excepción son subclases de cx_root, la sentencia CATCH cx_root es suficiente para interceptar cualquier excepción.

Secuencia de sentencias CATCH

Al escribir sentencias CATCH, debe colocar primero la clase (o clases) más específica y las más genéricas en último lugar. Si coloca una clase superior por encima de una de sus subclases, provocará un error de sintaxis. Esto se debe a que el sistema no ha podido procesar el bloque CATCH específico porque está eclipsado por el más genérico.

El suplemento INTO

Cada excepción se representa mediante un objeto. Puede colocar este objeto en una variable de referencia y trabajar con él, por ejemplo, para recuperar el texto de error de la clase de excepción utilizando el método get_text( ) como se muestra en el ejemplo.

Puede utilizar una declaración en línea en la sentencia CATCH para garantizar que la variable de referencia se declare con el tipo correcto.

Lo más común que hay que hacer con el objeto de excepción es llamar a su método get_text( ). Sin embargo, los objetos de excepción pueden poseer otros atributos y métodos para ayudarle a gestionar el error.

Las clases de excepción pueden tener atributos que describan de forma más precisa lo que ha fallado. Estos atributos se utilizan a menudo para rellenar los reserva-espacios de los mensajes. Defina un atributo en la sección pública de la clase de excepción con su nombre y tipo adecuados.

Para rellenar un atributo cuando se emite la excepción, necesita un parámetro de importación correspondiente del constructor de la clase de excepción. Puede generar este parámetro de importación mediante una corrección rápida. Sitúe el cursor en el nombre de método constructor y pulse Ctrl + 1. Seleccione la corrección rápida Volver a generar constructor.

Propagación de excepciones

Un método puede propagar una excepción a lo largo de la cadena de llamadas. En lugar de utilizar la sentencia CATCH para tratar la excepción, el método incluye la cláusula RAISING en su definición. Esto indica a los programas de llamada del método que se les puede transferir la excepción.

Si la excepción no se intercepta en ninguna parte de la cadena de llamadas, se producirá un error en tiempo de ejecución.

El atributo previous

A veces, dentro de una cadena de llamadas, un método interceptará una excepción y, en respuesta, emitirá una excepción diferente para que su propio llamador intercepte. Esto puede suceder, por ejemplo, si un framework emite una excepción que está demasiado orientada técnicamente para que la aplicación se procese. El método que desencadena su propia excepción puede transmitir la primera excepción. Puede hacerlo utilizando el atributo previous de la clase de excepción.

Cuando emite una excepción, puede transferir una instancia de una clase de excepción al parámetro de importación previous. Esto adjunta el objeto de excepción a la nueva excepción. Un método que intercepta la segunda excepción puede acceder al primer objeto de excepción utilizando el atributo público de solo lectura previous.

Como previous se implementa en la clase superior cx_root, está disponible en todas las clases de excepción.

Pruébelo: clases de excepción

  1. Cree una clase nueva que implemente la interfaz IF_OO_ADT_CLASSRUN.
  2. Copie el siguiente fragmento de código en la parte de implementación del método if_oo_adt_classrun~main( ).
    Code Snippet
    12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
    DATA number1 TYPE i VALUE 2000000000. DATA number2 TYPE p LENGTH 2 DECIMALS 1 VALUE '0.5'. DATA result TYPE i. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow. out->write( 'Arithmetic Overflow' ). CATCH cx_sy_zerodivide. out->write( 'Division by zero' ). ENDTRY. number2 = 0. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow. out->write( 'Arithmetic Overflow' ). CATCH cx_sy_zerodivide. out->write( 'Division by zero' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_overflow cx_sy_zerodivide. out->write( 'Arithmetic overflow or division by zero' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_sy_arithmetic_error. out->write( 'Caught both exceptions using their common superclass' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_root. out->write( 'Caught any exception using CX_ROOT' ). ENDTRY. TRY. result = number1 / number2. CATCH cx_root into data(Exception). out->write( 'Used INTO to intercept the exception object' ). out->write( 'The get_Text( ) method returns the following error text: ' ). out->write( Exception->get_text( ) ). ENDTRY.
  3. Active la clase con Ctrl + F3.
  4. Reproduzca con la codificación para familiarizarse con ella.

Trabajar con objetos de excepción

Puede mejorar su código accediendo a objetos de excepción, es decir, instancias de clases de excepción. Los parámetros de constructor se utilizan para fijar valores de atributo de objetos de excepción.

Modelo:

  • /LRN/CL_S4D401_OOS_FACTORY (clase global)

Solución:

  • /LRN/CL_S4D401_EXS_HANDLING (clase global)

Tarea 1: Copiar plantilla (opcional)

Copie la clase de modelo /LRN/CL_S4D401_OOS_FACTORY. Si ha finalizado el ejercicio anterior, puede omitir esta tarea y continuar editando su clase ZCL_##_SOLUTION.

Pasos

  1. Copie la clase /LRN/CL_S4D401_OOS_FACTORY en una clase de su propio paquete (nombre sugerido: ZCL_##_SOLUTION, donde ## representa su número de grupo).

    1. En el Explorador de proyectos, haga clic con el botón derecho en la clase /LRN/CL_S4D401_OOS_FACTORY para abrir el menú contextual.

    2. En el menú contextual, seleccione Duplicar....

    3. Introduzca el nombre del paquete en el campo Paquete. En el campo Nombre, introduzca ZCL_##_SOLUTION, donde ## representa su número de grupo.

    4. Seleccione Siguiente.

    5. Confirme la orden de transporte y seleccione Finalizar.

  2. Active la copia.

    1. Pulse Ctrl + F3 para activar la clase.

Tarea 2: Acceder a objetos de excepción

En su clase global, ajuste la implementación del método IF_OO_ADT_CLASSRUN~MAIN. Amplíe el tratamiento de excepciones al llamar el método factory GET_INSTANCE. En ambos bloques CATCH, reciba una referencia al objeto de excepción y extraiga el texto de excepción. Sustituya el texto literal para la salida de la consola por los textos de excepción.

Pasos

  1. Navegue a la implementación del método IF_OO_ADT_CLASSRUN~MAIN de su clase global.

    1. Abra la clase global y cambie a la pestaña Clase global.

  2. En la primera sentencia CATCH, deje un punto de variable de referencia en el objeto de excepción, es decir, la instancia de la clase de excepción CX_ABAP_INVALID_VALUE (nombre sugerido para la variable: exc_inv).

    Consejo

    Puede utilizar una declaración en línea para declarar la variable de referencia con el tipo correcto.
    1. Ajuste el código de la siguiente manera:

      ABAP
      1
      CATCH cx_abap_invalid_value INTO DATA(exc_inv).
    2. Para visualizar el tipo de variable exc_inv, sitúe el cursor en exc_inv y pulse F2.

  3. En el bloque CX_ABAP_INVALID_VALUE CATCH, comente la llamada del método out->write. Recupere el texto de excepción del objeto de excepción y utilícelo en una nueva llamada del método out->write.

    1. Ajuste el código de la siguiente manera:

      ABAP
      123
      CATCH cx_abap_invalid_value INTO DATA(exc_inv). * out->write( |Carrier { c_carrier_id } does not exist| ). out->write( exc_inv->get_text( ) ).
  4. Haga lo mismo con la segunda sentencia CATCH y el bloque CATCH (nombre sugerido para la variable de referencia: exc_auth).

    1. Ajuste el código de la siguiente manera:

      ABAP
      123
      CATCH cx_abap_auth_check_exception INTO DATA(exc_auth). * out->write( |No authorization to display carrier { c_carrier_id }| ). out->write( exc_auth->get_text( ) ).
  5. Active y pruebe su código. Ajuste el valor de la constante c_carrier_id para provocar las diferentes excepciones.

    1. Pulse Ctrl + F3 para activar el código.

    2. Pulse F9 para ejecutar el código como aplicación de consola.

    3. Fije el valor de la constante c_carrier_id en XX para provocar la excepción para un valor no válido.

    4. Fije el valor de la constante c_carrier_id en UA para provocar la excepción por falta de autorización.

Tarea 3: Gestionar grupos de excepciones

En la clase de test local LTCL_FIND_FLIGHTS, ajuste la implementación del método CLASS_SETUP. Al llamar el método factory GET_INSTANCE, trate todas las excepciones posibles en un solo bloque CATCH. En caso de excepción, proporcione al método de error el texto de excepción del objeto de excepción en lugar del mensaje de error genérico "No se puede instanciar lcl_carrier".

Pasos

  1. Navegue a la implementación del método CLASS_SETUP de la clase de test local LTCL_FIND_FLIGHTS.

    1. Cambie a la pestaña Clases de test.

    2. Desplácese hasta la sentencia METHOD class_setup.

  2. Después de llamar el método GET_INSTANCE, ajuste el tratamiento de excepciones. Comente el bloqueo de interceptación para la clase de excepción CX_ABAP_INVALID_VALUE y sustituya la clase de excepción CX_ABAP_AUTH_CHECK_EXCEPTION por CX_ROOT.

    1. Ajuste el código de la siguiente manera:

      ABAP
      1234567
      TRY. the_carrier = lcl_carrier=>get_instance( i_carrier_id = some_flight_data-carrier_id ). * CATCH cx_abap_invalid_value. * cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). CATCH cx_root. cl_abap_unit_assert=>fail( `Unable to instantiate lcl_carrier` ). ENDTRY.
  3. Añada una cláusula INTO a la sentencia CATCH con una variable de referencia declarada en línea (nombre sugerido para la variable: exc_root).

    1. Ajuste el código de la siguiente manera:

      ABAP
      1
      CATCH cx_root INTO DATA(exc_root).
    2. Para visualizar el tipo de variable exc_root, sitúe el cursor en exc_root y pulse F2.

  4. En el bloque CX_ROOT CATCH, utilice el texto de excepción como entrada para el método CL_ABAP_UNIT_ASSERT=>error.

    1. Ajuste el código de la siguiente manera:

      ABAP
      12
      CATCH cx_root INTO DATA(exc_root). cl_abap_unit_assert=>fail( exc_root->get_text( ) ).
  5. Active el código.

    1. Pulse Ctrl + F3.

Tarea 4: Fijar atributos de objetos de excepción

Ajuste la emisión de las excepciones en el método factory GET_INSTANCE. Si emite la excepción CX_ABAP_INVALID_VALUE, utilice un parámetro de constructor adecuado para incluir el ID de transportista no válido en el texto de excepción. Si emite la excepción CX_ABAP_AUTH_CHECK_EXCEPTION, utilice un parámetro de constructor adecuado para seleccionar un texto de excepción más adecuado.

Pasos

  1. Navegue a la implementación del método GET_INSTANCE de la clase local LCL_CARRIER.

    1. Por ejemplo, en el método IF_OO_ADT_CLASSRUN~MAIN, sitúe el cursor en get_instance y pulse F3.

  2. Analice la firma del método CONSTRUCTOR de la clase de excepción CX_ABAP_INVALID_VALUE.

    1. En la sentencia RAISE EXCEPTION, sitúe el cursor en CX_ABAP_INVALID_VALUE y pulse F2 para visualizar la información del elemento ABAP para la clase de excepción.

    2. En la ventana de diálogo, seleccione el constructor para visualizar la información de elemento para el método CONSTRUCTOR.

  3. Ajuste la sentencia RAISE EXCEPTION para la clase de excepción CX_ABAP_INVALID_VALUE. Proporcione el valor de parámetro de constructor con el ID de transportista no válido.

    Nota

    Debe realizar una conversión de tipo porque el valor y el i_carrier_id no tienen un tipo idéntico.
    1. Ajuste el código de la siguiente manera:

      ABAP
      123
      RAISE EXCEPTION TYPE cx_abap_invalid_value EXPORTING value = CONV #( i_carrier_id ).
  4. Ajuste la sentencia RAISE EXCEPTION para la clase de excepción CX_ABAP_AUTH_CHECK_EXCEPTION. Suministre el parámetro de constructor textid con la constante pública missing_Authorization de esa clase de excepción.

    1. Ajuste el código de la siguiente manera:

      ABAP
      1234
      RAISE EXCEPTION TYPE cx_abap_auth_check_exception EXPORTING textid = cx_abap_auth_check_exception=>missing_authorization.
  5. Active y pruebe su código. Ajuste el valor de la constante c_carrier_id para provocar las diferentes excepciones.

    1. Pulse Ctrl + F3 para activar el código.

    2. Pulse F9 para ejecutar el código como aplicación de consola.

    3. Fije el valor de la constante c_carrier_id en XX para provocar la excepción para un valor no válido.

    4. Fije el valor de la constante c_carrier_id en UA para provocar la excepción por falta de autorización.