2646165 - Exception CX_ADDRESS_BCS triggered - An Exception occurred

作者:郑德鼎 约 2 分钟阅读 更新日期:2024-02-22 2 年前更新 标签:PP, SD, 生产, 销售分销

2646165 - "Exception CX_ADDRESS_BCS triggered - An Exception occurred"

SAP Knowledge Base Article, Version: 3, Released On: 25.01.2021

Show Changes

ComponentBC-SRV-ADR

PriorityNormal

CategoryProblem

Release StatusReleased to Customer

Rated Helpful

(0 people)

Quality Rating



Symptom

You are receiving the error "Exception CX_ADDRESS_BCS triggered - An Exception occurred"

This is coming within the method CREATE_USER_HOME_ADDRESS within Class CL_CAM_ADDRESS_BCS

Environment

SAP NetWeaver

Release Independent

Reproducing the Issue

SE24 => Enter Class CL_CAM_ADDRESS_BCS

Test/Execute button

Enter Method CREATE_USER_HOME_ADDRESS

Enter the I_USER as an affected User and I_COMMTYPE as communication type (e.g. INT)

Execute and error will be thrown

Cause

There is an inconsistency between the SAP Office key (SO_KEY) of the User in the ADCP and SOUD tables. This can be checked in the tables in transaction SE16.

Resolution

To correct the issue, the inconsistency of the value of SAP Office key (SO_KEY) between ADCP and SOUD must be corrected.

Please run the report Z_OSSNOTE_570505 from note '570505 - Correction report for SO_KEY', which will resolve the inconsistency.

See Also

2627357 - Incorrect Sender details displayed for Send requests in transaction SOST

Keywords

Exception CX_ADDRESS_BCS triggered, An Exception occurred, CX_ADDRESS_BCS, SOUD, ADCP, SO Key, SO_KEY, CREATE_USER_HOME_ADDRESS, CL_CAM_ADDRESS_BCS, SAPoffice key,

Products

This document refers to

Attributes

Available Languages

日本語 (Machine Translation)

Português (Machine Translation)

Español (Machine Translation)

中文 (Machine Translation)

Français (Machine Translation)

Italiano (Machine Translation)

Русский (Machine Translation)

한국어 (Machine Translation)

Deutsch (Machine Translation)

Rate this document

Was this KBA helpful?

Yes

No

| Products | |

This document is not restricted to a product or product version | This document is not restricted to a product or product version | This document is not restricted to a product or product version | This document is not restricted to a product or product version

| SAP Note/KBA | Component | Title | |

| 2627357 | BC-SRV-COM | Incorrect Sender details displayed for Send requests in transaction SOST | |

| 570505 | BC-SRV-ADR | Correction report for SO_KEY | |

| Key | Value | |

| Other Components | BC-SRV-COM (Communication Services: Mail, Fax, SMS, Telephony) | |

来源说明:本文内容由「2646165 - Exception CX_ADDRESS_BCS triggered - An Exception occurred.docx」整理生成,仅用于内部技术分享与学习交流。

ABAP Cheat Sheet 补充内容

以下内容整理自 SAP 官方 ABAP 速查表(主题:Exceptions and Runtime Errors),作为本文的扩展补充资料。

Exceptions and Runtime Errors

This cheat sheet includes an overview about syntax in the context of exceptions and runtime errors in ABAP.

[!NOTE] Several code snippets in the cheat sheet use artifacts from the executable example.

Exceptions

Exceptions ...

  "The following statement raises an exception because of zero division. 
  "Since the exception is not handled, a runtime error occurs.
  DATA(div_result) = 1 / 0.

⬆️ back to top

Exception Classes

Exception classes ...

  METHODS divide
    IMPORTING num1              TYPE i
              num2              TYPE i
    RETURNING VALUE(div_result) TYPE decfloat34
    RAISING   cx_sy_zerodivide.
[!NOTE] - Non-class-based exceptions are obsolete and should no longer be used in new developments. See the guidelines (F1 docu for standard ABAP). - Unhandled exceptions raised by the ABAP runtime environment trigger a corresponding runtime error. For example, the exception class CX_SY_ZERODIVIDE causes the runtime error COMPUTE_INT_ZERODIVIDE. For self-defined exception classes, unhandled exceptions generally trigger the runtime error UNCAUGHT_EXCEPTION.

⬆️ back to top

Exception Categories

Exception classes are subclasses of three abstract classes, which in turn are subclasses of the root class CX_ROOT:

CX_ROOT
  |
  |--CX_STATIC_CHECK
  |
  |--CX_DYNAMIC_CHECK
  |
  |--CX_NO_CHECK

Notes on the superclasses of exception classes:

Superclass of Exception Classes Notes

CX_STATIC_CHECK

  • Users must handle exceptions.
  • Exceptions that may occur in procedures should be handled locally within the implementation or explicitly declared in the procedure interface so callers know what errors to expect.
  • Exception classes of type CX_STATIC_CHECK enforce this by performing a static check at compile time. Procedure users must handle the exception locally in a TRY control structure or declare it in their procedure interface to propagate the exception. If not, a warning is produced.

Example:

  • A method signature might look like this. The RAISING addition in method signatures declares one or more class-based exceptions that can be propagated to the caller.
  • When users implement the method, they are aware that an error might occur, and a specific exception can be raised.
  • CX_UUID_ERROR is a predefined exception class derived from CX_STATIC_CHECK. Method users should prepare their code accordingly.
  "Method definition using the RAISING parameter
   CLASS-METHODS get_uuid
      RETURNING VALUE(uuid) TYPE sysuuid_x16
      RAISING   cx_uuid_error.

  ...
 
  "Method implementation
  METHOD get_uuid.
    uuid = cl_system_uuid=>create_uuid_x16_static( ) .
  ENDMETHOD.

  ...
  
  "Method call: Somewhere in the code of a user that calls the method
  "Exception handled locally in a TRY control structure
   TRY.
      DATA(uuid) = get_uuid( ).

      CATCH cx_uuid_error.
        ...
    ENDTRY.

  "If the statement is specified without the TRY control structure, 
  "a warning is shown.
  DATA(uuid2) = get_uuid( ).

CX_DYNAMIC_CHECK

  • For exceptions that can be checked and avoided by preconditions:
  • Unlike exception classes derived from CX_STATIC_CHECK, exception classes derived from CX_DYNAMIC_CHECK do not enforce local handling or declaration in procedure interfaces.
  • However, proper exception handling is necessary when you cannot prevent the exceptions from being raised in your program logic.
  • Runtime checks verify whether local handling or explicit declaration in procedure interfaces are available only if the exception is raised.
  • If, at runtime, such an exception is neither locally handled nor properly declared in an interface and the exception is raised, a new exception of type CX_SY_NO_HANDLER is raised, with the PREVIOUS attribute referencing the original exception.

Example:

  • The predefined class CX_SY_ZERODIVIDE is derived from CX_SY_ARITHMETIC_ERROR, which is derived from CX_DYNAMIC_CHECK.
  • Operands in a calculation should be checked (e.g., ensuring the second operand is not 0 in a division) before performing the arithmetic operation to avoid exceptions.


  "Method definition using the RAISING parameter
  CLASS-METHODS divide
    IMPORTING num1              TYPE i
              num2              TYPE i
    RETURNING VALUE(div_result) TYPE decfloat34
    RAISING   cx_sy_zerodivide.

  ...
 
  "Method implementation
  METHOD divide.
    div_result = num1 / num2.
  ENDMETHOD.
 
  ...
  
  "Method call: Somewhere in the code of a user that calls the method
  "Unlike procedures specifying an exception class derived from CX_STATIC_CHECK,
  "procedures specifying an exception class derived from CX_DYNAMIC_CHECK do not
  "enforce the local handling of exceptions. So, the following statement does
  "not show a warning.
  DATA(div_result1) = divide( num1 = 5 num2 = 2 ).

  "Exception handled locally in a TRY control structure
  TRY.
      DATA(div_result2) = divide( num1 = 5 num2 = 0 ).
    CATCH cx_sy_zerodivide.
  ENDTRY.

CX_NO_CHECK

  • For errors that may occur anytime, cannot be handled locally in a meaningful way, or cannot be avoided even after a check.
  • An example of such an error is a lack of memory. If such exceptions were checked statically or dynamically, it would require specification in each procedure interface, which is not ideal for clear program structure.
  • Note that exceptions derived from CX_NO_CHECK are always implicitly declared in all procedure interfaces.

[!NOTE] - Basic rule: Use a suitable exception category (F1 docu for standard ABAP). - Directly deriving from CX_ROOT is not possible. - As covered in the following sections, exception classes have specific components so that exceptions can be evaluated.

⬆️ back to top

Components of Exception Classes

[!NOTE] - Further additions may be available depending on the exception object. - Usually, instances of exception classes are created when exceptions are raised. However, instances can also be created programmatically, e.g., with the NEW operator (if the classes are not abstract). - It is possible to define additional methods and attributes in exception classes, for example, for passing more information about error situations to handlers. Custom attributes should be defined as READ-ONLY. - Find examples in the section below, covering CATCH ... INTO ....

⬆️ back to top

Raising Class-Based Exceptions

      DATA(div_result) = 1 / 0.

Syntax examples for raising exceptions programmatically:

[!NOTE] More variants of the statements shown are possible. They are covered in a separate section below because they relate to topics covered in the following sections.
*&---------------------------------------------------------------------*
*& RAISE EXCEPTION statements 
*&---------------------------------------------------------------------*

"RAISE EXCEPTION statement with the TYPE addition, specifying
"the name of a visible exception class; an exception
"object is created (if necessary, see the ABAP Keyword Documentation
"for more details)
RAISE EXCEPTION TYPE cx_sy_zerodivide.

"RAISE EXCEPTION statement specifying an exception object (an object
"reference variable pointing to an exception class)
DATA(exc) = NEW cx_sy_zerodivide( ).
RAISE EXCEPTION exc.

"Creating an exception object inline using the NEW operator
RAISE EXCEPTION NEW cx_sy_zerodivide( ).

"Note: Instances of abstract classes cannot be created. So, the
"following statements are not possible.
"RAISE EXCEPTION NEW cx_sy_arithmetic_error( ).
"RAISE EXCEPTION NEW cx_static_check( ).
"RAISE EXCEPTION NEW cx_dynamic_check( ).
"RAISE EXCEPTION NEW cx_no_check( ).
"RAISE EXCEPTION NEW cx_root( ).

"Dynamic creation of an exception object with CREATE OBJECT
DATA dyn_exc TYPE REF TO cx_root.
CREATE OBJECT dyn_exc TYPE ('CX_SY_ZERODIVIDE').
RAISE EXCEPTION dyn_exc.

*&---------------------------------------------------------------------*
*& COND/SWITCH operators with THROW addition
*&---------------------------------------------------------------------*

"THROW addition in conditional expressions with the COND and SWITCH operators
"enabling raising class-based exceptions in operand positions
"The addition works like RAISE EXCEPTION TYPE statements.

"COND operator
DATA(int1) = 1.
DATA(int2) = 0.
"The statement considers ABAP "allowing" zero division when both operands are 0.
DATA(res1) = COND decfloat34( WHEN ( int1 <> 0 AND int2 <> 0 ) OR ( int1 = 0 AND int2 <> 0 ) THEN int1 / int2
                              ELSE THROW cx_sy_zerodivide( ) ).

"SWITCH operator
"The following example shows SWITCH with the THROW addition
"and uses cx_sy_zerodivide for demo purposes.
DO 5 TIMES.
  DATA(num) = SWITCH #( sy-index
                        WHEN 1 THEN `one`
                        WHEN 2 THEN `two`
                        WHEN 3 THEN `three`
                        WHEN 4 THEN `four`
                        ELSE THROW cx_sy_zerodivide( ) ).
ENDDO.

⬆️ back to top

Handling Exceptions Using TRY Control Structures

TRY Control Structures

  TRY.
      ...
      "Statement block
    CATCH ...
      ... "Statements  
  ENDTRY.
  TRY.    
    DATA(div1) = 1 / 0.

    "Predefined exception class cx_sy_zerodivide as suitable exception class to be used here.
    "If the exception is not handled, the program is terminated and the runtime error
    "COMPUTE_INT_ZERODIVIDE occurs.
    CATCH cx_sy_zerodivide.
      ... "CATCH block
  ENDTRY.

  "Example for catching an exception in the context of a table expression
  TRY.
    "Copying a line of an internal table
    DATA(line) = some_itab[ 12345 ].

    "Predefined exception class cx_sy_itab_line_not_found as suitable exception class to be used here.
    "If the exception is not handled, the program is terminated and the runtime error
    "ITAB_LINE_NOT_FOUND occurs.
    CATCH cx_sy_itab_line_not_found.
      ... "CATCH block
  ENDTRY.

  "Multiple classes in a list and CATCH blocks can be specified
  "Note: If there are multiple CATCH blocks for exceptions that are in an inheritance
  "relationship, you must pay attention that the more special exceptions are specified
  "before the more general ones.
  TRY.
      ... "TRY block
    CATCH cx_abc cx_bla cx_blabla.
      ... "CATCH block
    CATCH cx_la cx_lala.
      ... "CATCH block
    CATCH cx_lalala.
      ... "CATCH block
  ENDTRY.
    TRY.
      "TRY block
      DATA(div2) = 1 / 0.

      "A CATCH block is in this example not only valid for cx_sy_zerodivide as specified above
      "but also for all derived exceptions classes.
      "In the following CATCH block, the predefined exception class cx_sy_arithmetic_error
      "is specified. cx_sy_zerodivide is derived from cx_sy_arithmetic_error.
      "Hence, cx_sy_arithmetic_error can be specified and handle the exception, too.
      CATCH cx_sy_arithmetic_error.
        ... "CATCH block
    ENDTRY.

    "Example demonstrating the exception root class cx_root specifying after CATCH to 
    "catch all catchable exception.
     DO 3 TIMES.
      TRY.
          CASE sy-index.
            WHEN 1.
              RAISE EXCEPTION TYPE cx_sy_zerodivide.
            WHEN 2.
              RAISE EXCEPTION TYPE cx_uuid_error.
            WHEN 3.
              RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
          ENDCASE.
        CATCH cx_root.
        "Instead of explicit specification of potential exception classes involved
        "CATCH cx_sy_zerodivide cx_uuid_error cx_sy_itab_line_not_found.
      ENDTRY.
    ENDDO.

⬆️ back to top

CATCH ... INTO ...: Storing Exception Objects and Evaluation

Example:

"Note the specification of the root class cx_root
DATA exception TYPE REF TO cx_root. 

TRY.
    ... "TRY block

  "Storing a reference to the exception object.
  "Note: The type is cx_root since attributes and methods of the root class that are defined there can be accessed.
  CATCH INTO exception.
    ... "CATCH block
ENDTRY.

"Inline creation of exception object reference and getting exception texts
TRY.
    ... "TRY block

  "The object reference variable can be created inline, for example, using DATA(...).
  CATCH cx_sy_arithmetic_error INTO DATA(error_oref).
    ... "catch block

ENDTRY.

*******************************************************************************************************************
"Copyable example
DO 2 TIMES.
  TRY.
      IF sy-index = 1.
        DATA(div) = CONV decfloat34( 1 / 0 ).
      ELSE.
        DATA(powers) = ipow( base = 10 exp = 100 ).
      ENDIF.
    CATCH cx_sy_arithmetic_error INTO DATA(error_arithm).
      DATA(text) = error_arithm->get_text( ).
      "Using RTTI to retrieve the relative name of the class
      DATA(cl_name) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_object_ref( 
            error_arithm ) )->get_relative_name( ).
      
      "Results:
      "---- sy-index = 1 ----
      "text: "Division by zero"
      "cl_name = CX_SY_ZERODIVIDE
      "---- sy-index = 2 ----
      "text: Overflow in the operation IPOW
      "cl_name = CX_SY_ARITHMETIC_OVERFLOW
  ENDTRY.
ENDDO.

Examples for evaluating exception information accessible via components of the exception object specified after INTO. See Components of Exception Classes.

TRY.
    DATA(div_result) = CONV decfloat34( 1 / 0 ).
  CATCH cx_sy_zerodivide INTO DATA(error).
    "Getting short text
    DATA(text) = error->get_text( ).

    "Getting source code position of where the error occured
    error->get_source_position(
      IMPORTING
        program_name = DATA(program_name)
        include_name = DATA(include_name)
        source_line  = DATA(source_line)
    ).
ENDTRY.

Demonstrating the instance attribute previous:

"Demonstrating the instance attribute 'previous' with
"nested TRY control structures.
"Consider the following scenario: A method is called and
"an exception is raised. Once evaluated, another exception
"is raised, and the previous exception (i.e. a reference to
"the previous exception object) is passed on to the caller.
"The caller can then evaluate the exceptions raised.
"The following example includes nested TRY control structures.
"In CATCH blocks, further exceptions are raised. There, the
"exception object is passed. In a WHILE loop, several pieces
"of information are retrieved, including the use of RTTI. 
"Once the information has been retrieved, the previous attribute
"is used to assign the previous exception object. Note the cast.

DATA info TYPE string_table.

TRY.
    TRY.
        TRY.
            RAISE EXCEPTION NEW cx_sy_zerodivide( ).
          CATCH cx_sy_zerodivide INTO DATA(err1).
            RAISE EXCEPTION NEW cx_sy_arithmetic_overflow( previous = err1 ).
        ENDTRY.
      CATCH cx_sy_arithmetic_overflow INTO DATA(err2).
        RAISE EXCEPTION NEW cx_sy_itab_line_not_found( previous = err2 ).
    ENDTRY.
  CATCH cx_sy_itab_line_not_found INTO DATA(err3).
ENDTRY.

DATA(acc_err) = CAST cx_root( err3 ).
WHILE acc_err IS BOUND.
  DATA(txt) = acc_err->get_text( ).

  acc_err->get_source_position(
    IMPORTING
      program_name = DATA(prog_name)
      include_name = DATA(incl_name)
      source_line  = DATA(src_line)
  ).

  "Using RTTI to gather more information on the exception
  "See the Dynamic Programming cheat sheet about RTTI.
  DATA(tdo) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_object_ref( acc_err ) ).
  DATA(cl_relative_name) = tdo->get_relative_name( ).
  DATA(attributes) = tdo->attributes.
  DATA(superclass) = tdo->get_super_class_type( )->get_relative_name( ).

  "Populating info table
  APPEND repeat( val = `-` occ = 110 ) TO info.
  APPEND |Text: { txt }| TO info.
  APPEND |Position of raised exception: { prog_name } / { incl_name } / { src_line }| TO info.
  APPEND |Exception class name: { cl_relative_name }| TO info.
  APPEND |Superclass of exception class: { superclass }| TO info.

  "Using the previous attribute to assign the previous exception
  "object
  acc_err = acc_err->previous.
  "If there was no cast to cx_root, a cast would be required here,
  "for example, as follows.
  "acc_err = CAST #( acc_err->previous ).
ENDWHILE.

⬆️ back to top

CLEANUP Statements

Examples:

"The following example shows nested TRY control structures.
"The inner TRY control structure includes a CLEANUP block.
"The example demonstrates that an exception raised cannot
"be handled by the TRY control structure where it is raised.
"No meaningful 'cleanup' action is performed in the example's
"CLEANUP block. For demonstration purposes, an info table is 
"populated demonstrating the execution of the block.

DATA info_tab TYPE string_table.
DATA cleanup TYPE REF TO cx_root.
DO 2 TIMES.
  APPEND |---- Loop pass { sy-index } ----| TO info_tab.
  TRY.
      TRY.

          IF sy-index = 1.
            DATA(calc) = CONV decfloat34( 1 / 0 ).
          ELSE.
            DATA(strtab) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ).
            DATA(line_4) = strtab[ 4 ].
          ENDIF.

        CATCH cx_sy_zerodivide INTO cleanup.
          APPEND `---- Catching cx_sy_zerodivide ----` TO info_tab.
          APPEND cleanup->get_text( ) TO info_tab.

        CLEANUP.
          APPEND `#### Executing CLEANUP block ####` TO info_tab.
          APPEND `d` TO strtab.

          "CLEANUP block must be executed completely
          "Leaving the block prematurely causes a runtime error. If it is statically known
          "that it is not possible to return to the block, a syntax error is shown.
          "So, the following statement is not allowed in the CLEANUP block.
          "RETURN.
      ENDTRY.
    CATCH cx_sy_itab_line_not_found INTO cleanup.
      APPEND `---- Catching cx_sy_itab_line_not_found ----` TO info_tab.
      APPEND cleanup->get_text( ) TO info_tab.
      TRY.
          line_4 = strtab[ 4 ].
          APPEND `Since the row was added in the CLEANUP block, it is now in the table.` TO info_tab.
        CATCH cx_sy_itab_line_not_found INTO DATA(line_not_found).
          APPEND `The row is not in the table.` TO info_tab.
      ENDTRY.
  ENDTRY.
ENDDO.

*&---------------------------------------------------------------------*
*& INTO addition
*&---------------------------------------------------------------------*

"The example is the same as above. Here, the CLEANUP statement is specified
"with the addition INTO. If required, you can evaluate the exception information
"as shown above.

DATA info_tab_b TYPE string_table.
DATA cleanup_b TYPE REF TO cx_root.
DO 2 TIMES.
  APPEND |---- Loop pass { sy-index } ----| TO info_tab_b.
  TRY.
      TRY.

          IF sy-index = 1.
            DATA(calc_b) = CONV decfloat34( 1 / 0 ).
          ELSE.
            DATA(strtab_b) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ).
            DATA(line_4_b) = strtab_b[ 4 ].
          ENDIF.

        CATCH cx_sy_zerodivide INTO cleanup_b.
          APPEND `---- Catching cx_sy_zerodivide ----` TO info_tab_b.
          APPEND cleanup_b->get_text( ) TO info_tab_b.

        CLEANUP INTO cleanup_b.
          APPEND `#### Executing CLEANUP block ####` TO info_tab_b.
          "USing RTTI to find out the absolute name of the class of the raised execption
          DATA(cl_name) = cl_abap_classdescr=>get_class_name( p_object = cleanup_b ).
          APPEND cl_name TO info_tab_b.
          APPEND `d` TO strtab_b.

          "CLEANUP block must be executed completely
          "Leaving the block prematurely causes a runtime error. If it is statically known
          "that it is not possible to return to the block, a syntax error is shown.
          "So, the following statement is not allowed in the CLEANUP block.
          "RETURN.
      ENDTRY.
    CATCH cx_sy_itab_line_not_found INTO cleanup_b.
      APPEND `---- Catching cx_sy_itab_line_not_found ----` TO info_tab_b.
      APPEND cleanup_b->get_text( ) TO info_tab_b.
  ENDTRY.
ENDDO.

⬆️ back to top

RETRY Statements

RETRY statements ...

Example:

"The following example includes a division of 1 by another number.
"In a DO loop 1 is divided by all numbers from 10 to -10.
"When the zero division exception is caught, the exception cause is
"removed by changing the first operand's value to 0, too (Note: ABAP
"'allows' zero division) before the RETRY statement. The RETRY statement
"triggers the execution of the TRY control structure again, now
"resulting in 0 as division result. After that, and to have a self-contained
"example, the operand value is changed back to 1.
DATA division_result_tab TYPE TABLE OF decfloat34 WITH EMPTY KEY.
DATA(number1) = 1.
DATA(number2) = 11.
DATA division_result TYPE decfloat34.
DO.
  number2 -= 1.
  TRY.
      division_result = number1 / number2.
      APPEND division_result TO division_result_tab.
    CATCH cx_sy_zerodivide.
      "Removing the exception cause by setting a value that
      "does not raise the zero division exception
      number1 = 0.
      DATA(retry_flag) = abap_true.
      "Processing the TRY control structure again
      RETRY.
  ENDTRY.

  "Resetting of number1 value to 1
  IF retry_flag = abap_true.
    number1 = 1.
    retry_flag = abap_false.
  ENDIF.

  IF sy-index = 21.
    EXIT.
  ENDIF.
ENDDO.

⬆️ back to top

RESUME Statements and RESUMABLE Additions

Example:

CLASS zcl_demo_abap DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.
  PROTECTED SECTION.
  PRIVATE SECTION.
    "The following demo method declaration shows one prerequisite of resumable
    "exceptions. The RAISING clause specifies a demo exception class with the
    "RESUMABLE addition.
    CLASS-METHODS meth_resumable
      IMPORTING num1              TYPE i
                num2              TYPE i
      RETURNING VALUE(div_result) TYPE string
      RAISING   RESUMABLE(zcx_demo_abap_error_b).
ENDCLASS.


CLASS zcl_demo_abap IMPLEMENTATION.

  METHOD if_oo_adt_classrun~main.

*&---------------------------------------------------------------------*
*& CATCH BEFORE UNWIND
*&---------------------------------------------------------------------*

    "Example using the method
    "The following example creates a table containing integers from -5 to 5. This
    "table is looped across to have different values for divisions. Here, this
    "value represents the second operand. The first operand is the sy-tabix
    "value. The result is added to an internal table. When the second operand's
    "value is 0, the exception is raised. In the CATCH BEFORE UNWIND block, the
    "is_resumable attribute is evaluated. An info message is added to the internal
    "table, and the processing continues after executing the RESUME statement.

    DATA restab TYPE string_table.
    TYPES ty_inttab TYPE TABLE OF i WITH EMPTY KEY.
    DATA(inttab) = REDUCE ty_inttab( INIT tab = VALUE ty_inttab( )
                                     FOR  i = -5 UNTIL i > 5
                                     NEXT tab = VALUE #( BASE tab ( i ) ) ).

    LOOP AT inttab INTO DATA(wa).
      TRY.
          DATA(divres) = meth_resumable(
            num1 = sy-tabix
            num2 = wa
          ).
          APPEND |{ sy-tabix } / { wa } = { divres }| TO restab.
        CATCH BEFORE UNWIND zcx_demo_abap_error_b INTO DATA(error_resume).
          DATA(is_resumable) = error_resume->is_resumable.
          IF is_resumable IS NOT INITIAL.
            APPEND |Exception raised. Is resumable? -> "{ is_resumable }"| TO restab.
            RESUME.
          ENDIF.
      ENDTRY.
    ENDLOOP.

    out->write( data = restab name = `restab` ).

*Content of the result table:
*1 / -5 = 0.2-
*2 / -4 = 0.5-
*3 / -3 = 1-
*4 / -2 = 2-
*5 / -1 = 5-
*Exception raised. Is resumable? -> "X"
*6 / 0 = No result. Resumed!
*7 / 1 = 7
*8 / 2 = 4
*9 / 3 = 3
*10 / 4 = 2.5
*11 / 5 = 2.2

  ENDMETHOD.

  METHOD meth_resumable.

    "Demo method implementation demonstrating a RAISE EXCEPTION statement
    "with the RESUMABLE addition (and an example for statement using the COND
    "operator commented out)

    IF num2 = 0 AND num1 <> 0.
      RAISE RESUMABLE EXCEPTION TYPE zcx_demo_abap_error_b.
      div_result = `No result. Resumed!`.
    ELSE.
      div_result = num1 / num2.
    ENDIF.

    "Statement with COND operator using RESUMABLE
    "div_result = COND #( WHEN num2 = 0 AND num1 <> 0 THEN num1 / num2
    "                     ELSE THROW RESUMABLE zcx_demo_abap_error( ) ).

  ENDMETHOD.

ENDCLASS.

⬆️ back to top

Using Messages as Exception Texts

⬆️ back to top

System Interfaces for Messages

[!NOTE] When you create global exception classes in ADT, and you specify one of the exception superclasses to inherit from in the creation wizard, the resulting class code contains required implementations such as the instance constructor.

⬆️ back to top

Excursion: MESSAGE Statements

Example:

"The following examples demonstrate several MESSAGE statements. 
"The message class from the executable demo example is used. So, 
"the content of msg shows the specified example text, and includes
"the specified parameters.

"After MESSAGE, a message type is specified (which is not of relevance in ABAP for Cloud
"Development). These types can be the following: A, E, I, S, W, or X. See the ABAP Keyword
"Documentation for information. For example, E representing an error message.
"The character is followed by the message number. The message class name is directly
"specified within a pair of parentheses.
MESSAGE e001(zdemo_abap_messages) INTO DATA(msg).
"msg: An error occured (Nr. 001)

DATA(msgid) = sy-msgid. "ZDEMO_ABAP_MESSAGES
DATA(msgty) = sy-msgty. "E

MESSAGE e004(zdemo_abap_messages)
        WITH 'A' 'B' 'C' 'D'
        INTO msg.
"msg: Message (Nr. 004) p1: "A" p2: "B" p3: "C" p4: "D"

msgid = sy-msgid. "ZDEMO_ABAP_MESSAGES
msgty = sy-msgty. "E
DATA(msgv1) = sy-msgv1. "A
DATA(msgv2) = sy-msgv2. "B
DATA(msgv3) = sy-msgv3. "C
DATA(msgv4) = sy-msgv4. "D

MESSAGE ID 'ZDEMO_ABAP_MESSAGES'
    TYPE 'E'
    NUMBER '005'
    WITH 'E' 'F' 'G' 'H'
    INTO msg.
"msg: E F G H

msgid = sy-msgid. "ZDEMO_ABAP_MESSAGES
msgty = sy-msgty. "E
msgv1 = sy-msgv1. "E
msgv2 = sy-msgv2. "F
msgv3 = sy-msgv3. "G
msgv4 = sy-msgv4. "H

⬆️ back to top

Syntax Variants of RAISE EXCEPTION/THROW

[!NOTE] - The code snippets below use exception classes, a message class and messages from the executable demo example. - The snippets include additions that are only available when exception classes implement the IF_T100_DYN_MSG interface. - In the executable example, zcx_demo_abap_error_a implements the IF_T100_MESSAGE interface and zcx_demo_abap_error_b implements IF_T100_DYN_MSG.
*&---------------------------------------------------------------------*
*& RAISE EXCEPTION statements 
*&---------------------------------------------------------------------*

"Multiple additions and variants are possible. The following examples
"demonstrate a selection.
"Note that the examples include additions that are only available when
"exception classes implement the if_t100_dyn_msg interface.

"----- TYPE addition -----
"Raises an exception of a specified exception class
RAISE EXCEPTION TYPE zcx_demo_abap_error_b.

"----- TYPE addition including EXPORTING -----
"Assigns actual parameters to input parameters of the instance constructor
"particularly for classes implementing if_t100_message. The example uses
"a constant structure having the same name as the exception class.
RAISE EXCEPTION TYPE zcx_demo_abap_error_a EXPORTING textid = zcx_demo_abap_error_a=>zcx_demo_abap_error_a.

"Assigning values to replace placeholders of a message (see the executable example)
"In this case, replacing the placeholders &1 and &2 in a message.
RAISE EXCEPTION TYPE zcx_demo_abap_error_a
  EXPORTING
    textid  = zcx_demo_abap_error_a=>error_003
    p_003_a = `a`
    p_003_b = `b`.

"----- Specifying an exception object -----
DATA(cx_oref) = NEW zcx_demo_abap_error_a( textid = zcx_demo_abap_error_a=>error_005
                                            p_005_a = `Some`
                                            p_005_b = `error` ).

RAISE EXCEPTION cx_oref.

"Object reference created inline
RAISE EXCEPTION NEW zcx_demo_abap_error_a( textid  = zcx_demo_abap_error_a=>error_004
                                            p_004_a = `f`
                                            p_004_b = `g` ).


"----- MESSAGE addition -----
"For passing message specification to an exception object
"Note that EXPORTING can also be specified
"After MESSAGE, a message type is specified (which is not of relevance in ABAP for Cloud
"Development). These types can be the following: A, E, I, S, W, or X. See the ABAP Keyword
"Documentation for information. For example, E representing an error message.
"The character is followed by the message number. The message class name is directly
"specified within a pair of parentheses.
RAISE EXCEPTION TYPE zcx_demo_abap_error_a MESSAGE e002(zdemo_abap_messages).

"----- MESSAGE, ID, TYPE, NUMBER additions -----
"Specifying the message class, the message type, and the message number following
"dedicated additions
"The example is an alternative to the one above.
RAISE EXCEPTION TYPE zcx_demo_abap_error_a MESSAGE ID 'ZDEMO_ABAP_MESSAGES' TYPE 'E' NUMBER '002'.

"Specifying the values using data objects, not as literals as above.
"Note that uppercase letters are expected.
DATA(msgid) = 'ZDEMO_ABAP_MESSAGES'.
DATA(msgtype) = 'E'.
DATA(msgnum) = '002'.

RAISE EXCEPTION TYPE zcx_demo_abap_error_a MESSAGE ID msgid TYPE msgtype NUMBER msgnum.

"----- WITH addition -----
"Placeholders are replaced by the values specified after WITH
"Note that the positions of the operands determine which placeholders are replaced.
"The first specified operand replaces &1 and so on.

RAISE EXCEPTION TYPE zcx_demo_abap_error_b MESSAGE e005(zdemo_abap_messages) WITH 'Hello' 'world'.

RAISE EXCEPTION TYPE zcx_demo_abap_error_b MESSAGE ID 'ZDEMO_ABAP_MESSAGES'
                                                   TYPE 'E'
                                                   NUMBER '004'
                                                   WITH 'abc' 'def' 'ghi'.

"----- USING MESSAGE addition -----
"Implicitly passing message properties
"The examples show MESSAGE statement before RAISE EXCEPTION
"statements.
"In ABAP for Cloud Development, the message must be stored in
"a data object using the INTO addition.

MESSAGE ID 'ZDEMO_ABAP_MESSAGES' TYPE 'E' NUMBER '004'
        WITH 'abc' 'def' 'ghi' 'jkl'
        INTO DATA(msg1).

RAISE EXCEPTION TYPE zcx_demo_abap_error_b USING MESSAGE.

DATA: mid     TYPE sy-msgid VALUE 'ZDEMO_ABAP_MESSAGES',
      mtype   TYPE sy-msgty VALUE 'E',
      msg_num TYPE sy-msgno VALUE '002'.

MESSAGE ID mid TYPE mtype NUMBER msg_num INTO DATA(msg2).

RAISE EXCEPTION TYPE zcx_demo_abap_error_b USING MESSAGE.

"Alternative MESSAGE statement
MESSAGE e002(zdemo_abap_messages) INTO DATA(msg3).

RAISE EXCEPTION TYPE zcx_demo_abap_error_b USING MESSAGE.

"Alternative MESSAGE statement
"Here, specifying the WITH addition.
MESSAGE e005(zdemo_abap_messages) WITH 'a' 'b' 'c' 'd' INTO DATA(msg4).

RAISE EXCEPTION TYPE zcx_demo_abap_error_b USING MESSAGE.

"The RAISE EXCEPTION statement with USING MESSAGE can be considered
"as a short form of the following statement. Note that with the
"MESSAGE statement the system fields are populated.
MESSAGE e005(zdemo_abap_messages) WITH 'a' 'b' 'c' 'd' INTO DATA(msg5).

RAISE EXCEPTION TYPE zcx_demo_abap_error_b MESSAGE ID sy-msgid
                                                   TYPE sy-msgty
                                                   NUMBER sy-msgno
                                                   WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

*&---------------------------------------------------------------------*
*& COND operator, THROW addition 
*&---------------------------------------------------------------------*

DATA(flag) = 'X'.

"Specifying the exception class after THROW including a mandatory pair of parentheses
"even if no messages or actual parameters are passed. EXPORTING cannot be specified.
DATA(cond_w_throw_1) = COND #( WHEN flag IS INITIAL THEN `works`
                               ELSE THROW zcx_demo_abap_error_a( ) ).

"Passing actual parameters
DATA(cond_w_throw_2) = COND #( WHEN flag IS INITIAL THEN `works`
                               ELSE THROW zcx_demo_abap_error_a( textid  = zcx_demo_abap_error_a=>error_004
                                                                 p_004_a = `cond_a`
                                                                 p_004_b = `cond_b` ) ).

"MESSAGE addition
DATA(cond_w_throw_3) = COND #( WHEN flag IS INITIAL THEN `works`
                               ELSE THROW zcx_demo_abap_error_a( MESSAGE e005(zdemo_abap_messages)
                                                                 p_005_a = `An exception raised with COND` )  ).

DATA(cond_w_throw_4) = COND #( WHEN flag IS INITIAL THEN `works`
                               ELSE THROW zcx_demo_abap_error_b( MESSAGE e005(zdemo_abap_messages)
                                                                 WITH 'Lorem' 'ipsum' )  ).

"MESSAGE addition including ID, TYPE, NUMBER
DATA(cond_w_throw_5) = COND #( WHEN flag IS INITIAL THEN `works`
                               ELSE THROW zcx_demo_abap_error_a( MESSAGE ID 'ZDEMO_ABAP_MESSAGES'
                                                                 TYPE 'E'
                                                                 NUMBER '002' ) ).

DATA(cond_w_throw_6) =  COND #( WHEN flag IS INITIAL THEN `works`
                                ELSE THROW zcx_demo_abap_error_a( MESSAGE ID 'ZDEMO_ABAP_MESSAGES'
                                                                          TYPE 'E'
                                                                          NUMBER '005'
                                                                          p_005_a = `blabla` ) ).

"MESSAGE addition including ID, TYPE, NUMBER, WITH
DATA(cond_w_throw_7) = COND #( WHEN flag IS INITIAL THEN `works`
                               ELSE THROW zcx_demo_abap_error_b( MESSAGE ID 'ZDEMO_ABAP_MESSAGES'
                                                                         TYPE 'E'
                                                                         NUMBER '005'
                                                                         WITH `lorem ipsum` ) ).

"USING MESSAGE addition
MESSAGE e005(zdemo_abap_messages) WITH 'Some message' INTO DATA(msg6).

DATA(cond_w_throw_8) = COND #( WHEN flag IS INITIAL THEN `works`
                               ELSE THROW zcx_demo_abap_error_b( USING MESSAGE ) ).

*&---------------------------------------------------------------------*
*& SWITCH operator, THROW addition 
*&---------------------------------------------------------------------*

DATA(switch_w_throw_1) = SWITCH #( flag WHEN '' THEN `works`
                                   ELSE THROW zcx_demo_abap_error_a( ) ).

DATA(switch_w_throw_2) = SWITCH #( flag WHEN '' THEN `works`
                                   ELSE THROW zcx_demo_abap_error_a( textid  = zcx_demo_abap_error_a=>error_004
                                                                     p_004_a = `switch_a`
                                                                     p_004_b = `switch_b` ) ).

DATA(switch_w_throw_3) = SWITCH #( flag WHEN '' THEN `works`
                                   ELSE THROW zcx_demo_abap_error_a( MESSAGE e005(zdemo_abap_messages)
                                                                     p_005_a = `An exception raised with SWITCH` ) ).

DATA(switch_w_throw_4) = SWITCH #( flag WHEN '' THEN `works`
                                   ELSE THROW zcx_demo_abap_error_b( MESSAGE e005(zdemo_abap_messages)
                                                                     WITH 'Test' 'message' ) ).

DATA(switch_w_throw_5) = SWITCH #( flag WHEN '' THEN `works`
                                   ELSE THROW zcx_demo_abap_error_a( MESSAGE ID 'ZDEMO_ABAP_MESSAGES'
                                                                             TYPE 'E'
                                                                             NUMBER '005'
                                                                             p_005_a = `lorem ipsum` ) ).

DATA(switch_w_throw_6) = SWITCH #( flag WHEN '' THEN `works`
                                   ELSE THROW zcx_demo_abap_error_b( MESSAGE ID 'ZDEMO_ABAP_MESSAGES'
                                                                                 TYPE 'E'
                                                                                 NUMBER '005'
                                                                                 WITH `lorem ipsum` ) ).

MESSAGE e005(zdemo_abap_messages) WITH 'Some message' INTO DATA(msg7).

DATA(switch_w_throw_7) = SWITCH #( flag WHEN '' THEN `works`
                                   ELSE THROW zcx_demo_abap_error_b( USING MESSAGE ) ).

⬆️ back to top

Runtime Errors

Runtime errors ...

Example of a catchable exception not handled:

  Short Text  Division by 0 (type I or INT8)  
  Runtime Error  COMPUTE_INT_ZERODIVIDE  
  Exception  CX_SY_ZERODIVIDE    
  Program  ZCL_DEMO_ABAP=================CP
  ...

⬆️ back to top

Programmatically Raising Runtime Erros

RAISE SHORTDUMP TYPE cx_sy_zerodivide.

DATA(flag) = 'X'.
DATA(cond_w_throw_shortdump) = COND #( WHEN flag IS INITIAL THEN `works`
                                       ELSE THROW SHORTDUMP zcx_demo_abap_error_b( ) ).

DATA(switch_w_throw_shortdump) = SWITCH #( flag WHEN '' THEN `works`
                                           ELSE THROW SHORTDUMP zcx_demo_abap_error_b( ) ).

⬆️ back to top

Assertions

"The ASSERT keyword is followed by a logical expression.
"If the expression is false, the program is terminated and an uncatchable exception is raised
"resulting in the runtime error ASSERTION_FAILED.

DATA(number) = 0.
ASSERT number IS INITIAL.
ASSERT number > -1.
number = 1.
ASSERT number = 1.

DATA(flag) = abap_false.
"Raises a runtime error
ASSERT flag = abap_true.

⬆️ back to top

Excursions

Local Exception Classes

Class include Code

Global class

CLASS zcl_demo_abap DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.
  PROTECTED SECTION.
  PRIVATE SECTION.
    METHODS raise_local_exception IMPORTING num TYPE i
                                  RAISING   lcx_error.
ENDCLASS.


CLASS zcl_demo_abap IMPLEMENTATION.

  METHOD if_oo_adt_classrun~main.
    DO 6 TIMES.
      TRY.
          raise_local_exception( sy-index ).
        CATCH lcx_error INTO DATA(error).
          out->write( error->get_text( ) ).
      ENDTRY.
    ENDDO.
  ENDMETHOD.

  METHOD raise_local_exception.
    CASE num.
      WHEN 1.
        RAISE EXCEPTION TYPE lcx_error EXPORTING textid = lcx_error=>lcx_error.
      WHEN 2.
        RAISE EXCEPTION TYPE lcx_error EXPORTING textid = lcx_error=>some_error text = `Some error text`.
      WHEN 3.
        RAISE EXCEPTION TYPE lcx_error MESSAGE e002(zdemo_abap_messages).
      WHEN 4.
        RAISE EXCEPTION TYPE lcx_error MESSAGE e005(zdemo_abap_messages) WITH 'Some' 'error' 'occurred'.
      WHEN 5.
        RAISE EXCEPTION TYPE lcx_error MESSAGE ID 'ZDEMO_ABAP_MESSAGES' TYPE 'E' NUMBER '005' WITH 'Hello' 'world'.
      WHEN OTHERS.
        "Default message
        RAISE EXCEPTION TYPE lcx_error.
    ENDCASE.
  ENDMETHOD.

ENDCLASS.

Class-Relevant Local Types tab (CCDEF include)

CLASS lcx_error DEFINITION INHERITING FROM cx_static_check.
  PUBLIC SECTION.
    INTERFACES if_t100_dyn_msg.

    CONSTANTS:
      BEGIN OF lcx_error,
        msgid TYPE symsgid VALUE 'ZDEMO_ABAP_MESSAGES',
        msgno TYPE symsgno VALUE '001',
        attr1 TYPE scx_attrname VALUE '',
        attr2 TYPE scx_attrname VALUE '',
        attr3 TYPE scx_attrname VALUE '',
        attr4 TYPE scx_attrname VALUE '',
      END OF lcx_error.

    CONSTANTS:
      BEGIN OF some_error,
        msgid TYPE symsgid VALUE 'ZDEMO_ABAP_MESSAGES',
        msgno TYPE symsgno VALUE '005',
        attr1 TYPE scx_attrname VALUE 'TEXT',
        attr2 TYPE scx_attrname VALUE '',
        attr3 TYPE scx_attrname VALUE '',
        attr4 TYPE scx_attrname VALUE '',
      END OF some_error.

    DATA text TYPE string READ-ONLY.

    METHODS constructor
      IMPORTING
        textid   LIKE if_t100_message=>t100key OPTIONAL
        previous LIKE previous OPTIONAL
        text     TYPE string OPTIONAL.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

Local Types tab (CCIMP include)

CLASS lcx_error IMPLEMENTATION.
  METHOD constructor ##ADT_SUPPRESS_GENERATION.
    super->constructor( previous = previous ).

    me->text = text.
    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.

⬆️ back to top

Messages in RAP

The following example is from an ABAP EML cheat sheet example. Here, the standard implementation is used.

...
APPEND VALUE #( %tky = <fs_res>-%tky
                %msg = new_message_with_text(
                  severity = if_abap_behv_message=>severity-error
                  text = 'Validation failed!' )
              ) TO reported-root.
...              

⬆️ back to top

Violations of ABAP Contract Checks Causing Runtime Errors

ABAP contract checks include ...

Example:

    DELETE from zdemo_abap_rapt1.

    MODIFY ENTITIES OF zdemo_abap_rap_ro_m
        ENTITY root
        CREATE FIELDS ( key_field field1 field2 field3 field4 )
        WITH VALUE #( ( "%cid = 'cid1'
                        key_field = 1
                        field1    = 'aaa'
                        field2    = 'bbb'
                        field3    = 10
                        field4    = 11 ) )
        MAPPED FINAL(mapped)
        FAILED FINAL(failed)
        REPORTED FINAL(reported).

    COMMIT ENTITIES.

    SELECT SINGLE * from zdemo_abap_rapt1 where key_field = 1 into @FINAL(entry).

Example:

    "Activating the modify transactional phase
    cl_abap_tx=>modify( ).

    "The following database modification statement is not allowed in the
    "modify transactional phase. In certain contexts, e.g. in ABAP Cloud,
    "the runtime error BEHAVIOR_ILLEGAL_STMT_IN_CALL occurs.
    MODIFY zdemo_abap_carr FROM TABLE @( VALUE #(
        ( carrid = 'XY'
          carrname = 'XY Airlines'
          currcode = 'EUR'
          url =  'some_url' ) ) ).

    ...

    "Activating the save transactional phase
    cl_abap_tx=>save( ).

    "In this phase, database modifications are allowed.
    MODIFY zdemo_abap_carr FROM TABLE @( VALUE #(
        ( carrid = 'XY'
          carrname = 'XY Airlines'
          currcode = 'EUR'
          url =  'some_url' ) ) ).
    ...

⬆️ back to top

Classic Exceptions

Example:

TRY.
    cl_abap_typedescr=>describe_by_name( EXPORTING p_name = 'CL_THAT_DOES_NOT_EXIST'
                                         RECEIVING p_descr_ref = DATA(tdo_type)
                                         EXCEPTIONS type_not_found = 4 ).

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_demo_abap_error_b MESSAGE e005(zdemo_abap_messages) WITH 'Type not found'.
    ELSE.
      DATA(tdo_cl) = CAST cl_abap_classdescr( tdo_type ).

      "Getting more type information; find more information in the Dynamic Programming cheat sheet
      ...
    ENDIF.
  CATCH zcx_demo_abap_error_b INTO DATA(err).
    DATA(text) = err->get_text( ).
ENDTRY.

⬆️ back to top

More Information

ABAP Keyword Documentation

Executable Example

zcl_demo_abap_error_handling

[!NOTE] - The example involves the following artifacts: - One executable class zcl_demo_abap_error_handling - Two self-defined example exception classes zcx_demo_abap_error_a and zcx_demo_abap_error_b (one implements the IF_T100_DYN_MSG, the other implements IF_T100_MESSAGE) - One message class zdemo_abap_messages with 5 message texts that are used as exception texts - The example explores syntax described and uses code snippets in the cheat sheet. It does not represent best practice implementations, and only focuses on demonstrating ABAP syntax. - The executable example of the Program Flow Logic cheat sheet also includes examples with error handling. - The steps to import and run the code are outlined here. - Disclaimer
来源说明:本节内容来源:SAP-samples/abap-cheat-sheets (GitHub),原作者 SAP。原 Markdown 文件:27_Exceptions.md。版权归原作者所有。