Abap динамическая ошибка

Что тут нужно сделать?

Категория Внутренняя ошибка ядра
ДинамОшибка DDIC_TYPE_INCONSISTENCY
Прикладной компонент BC-ABA-LA
Дата и время 03.07.2013 18:04:43

Краткий текст
Inconsistency in the dictionary for the structure «COEP_ONLY».

Что произошло?
Error in the SAP kernel.

The current ABAP «ZBPC_EKP_R» program had to be terminated because the
ABAP processor detected an internal system error.

Что Вы можете сделать?
Note which actions and input led to the error.

For further help in handling the problem, contact your SAP administrator
.

You can use the ABAP dump analysis transaction ST22 to view and manage
termination messages, in particular for long term reference.

Анализ ошибки
There is an internal system error.
eliminated with ABAP/4.

There is an inconsisteny for the DDIC structure «COEP_ONLY», the corresponding
Dictionary runtime object (NAMETAB) is incorrect.

The number of components of the structure (NAMETAB component «fldcnt»)
is specified as 77. If all the substructures are resolved and the
actual total number of components is calculated recursively, a different
value is returned.

Указания по устранению ошибки
The error was probably caused by changes being made to the
DDIC structure «COEP_ONLY» or one of its substructures and an error occurred
afterwards at activation. Check the runtime object of the structure «COEP_ONLY»
in the Dictionary to analyze the exact cause of the error.

If the program RSNTABCONSISTENCY or its predecessor RSDDCHECK exists in
your system, you can check structure «COEP_ONLY» with the help of one of these
programs.

If you cannot solve the problem yourself and want to send an error
notification to SAP, include the following information:

1. The description of the current problem (short dump)

To save the description, choose «System->List->Save->Local File
(Unconverted)».

2. Corresponding system log

Display the system log by calling transaction SM21.
Restrict the time interval to 10 minutes before and five minutes
after the short dump. Then choose «System->List->Save->Local File
(Unconverted)».

3. If the problem occurs in a problem of your own or a modified SAP
program: The source code of the program
In the editor, choose «Utilities->More
Utilities->Upload/Download->Download».

4. Details about the conditions under which the error occurred or which
actions and input led to the error.

Информация о месте прерывания
The termination occurred during generation of the ABAP/4 program «ZBPC_EKP_R».

The termination occurred in line 69
of the source code of program «ZBPC_EKP_R_TOP» (when calling the editor 690).

Внутренние указания
The termination was triggered in function «ab_RxDdicTypeError»
of the SAP kernel, in line 1068 of the module
«//bas/720_REL/src/krn/runt/abucutil.c#4».
The internal operation just processed is » «.
Internal mode was started at 20130703180443.
There is an inconsistency in the DDIC structure «COEP_ONLY», the corresponding
dictionary runtime object (NAMETAB) is incorrect.

The number of components of the structure (NAMETAB component «fldcnt»)
is specified using 77. If you dismantle all the substructures and
calculate the actual total number of all the components recursively
then the result is a different value.

The error was caused because structure «COEP_ONLY» or one of its substructures
was changed and an error occurred in the subsequent activation. Please
check the runtime object of the structure «COEP_ONLY» in the dictionary to
analysis the exact error cause.

If the program RSDDCHECK is available on your system, you can also use
it to check structure «COEP_ONLY».

imagesКогда мы создаем какой-либо многократно используемый компонент, например функциональный модуль или метод в классе, мы сталкиваемся с необходимостью обработки непредвиденных ситуаций (какой-либо входной параметр, оказался не заполненным или доступ к файлу не был получен и т.п.), т.е. тех ситуаций, после которых программа не может выполняться далее стандартным образом, либо требуется дополнительная обработка.

В приведенной статье рассматриваются способы вызова и обработки данных ситуаций, называемых исключениями.

В ABAP есть два основных способа работы с исключениями, классический способ заключается в вызове особых ситуаций описанных в ФМ или методе на отдельной закладке:

1

Классический способ может использоваться и в классах:

2

Новый способ основывается на ООП, где в качестве исключений используются классы (обратите внимание, что установлена галочка – классы исключений):

3

Хочется отметить, что новый способ был введен с версии SAP Web AS 6.10 и при создании новых функциональных модулей или методов рекомендуется использовать именно его. В данной статье не рассматриваются системные исключения и их обработка до введения классов исключений.

В RFC модулях в настоящее время используется классический способ обработки исключений. Не допускается одновременно использовать классический и основанный на классах, способы обработки исключений (в интерфейсе методов, процедур, функций).

Классический способ обработки исключений

При вызове исключения, системное поле sy-subrc будет заполнено номером, под которым исключение было обозначено при вызове ФМ, метода или процедуры:

CALL FUNCTION ...

...

EXCEPTIONS

  Ошибка1 = 1

  Ошибка2 = 2.

Как правило, исключения вызываются с текстом сообщения, данный текст может быть описан статически – при вызове исключения оператором MESSAGE, либо динамически – путём получения текста из описания ФМ.

Так же исключение может быть вызвано без какого-либо текста (оператором RAISE ИмяИсключения), но данный способ лучше не использовать, т.к. вызов исключения должен как-то себя расшифровывать и говорить о том, что собственно произошло.

Напишем небольшой ФМ, рассчитывающий сумму двух чисел, оба параметра помечены как необязательные, если первый параметр не будет задан при вызове ФМ, система выдаст исключение – no_num_1.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

FUNCTION ZTEST_EXC.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH ‘Число 1 не указано, расчёт невозможен’ RAISING no_num_1.

  ENDIF.

  E_SUMM = i_num_1 + i_num_2.

ENDFUNCTION.

И программа для его вызова:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

DATA:

  gv_num_2 TYPE i VALUE 10,

  gv_summ  TYPE i.

CALL FUNCTION ‘ZTEST_EXC’

  EXPORTING

    i_num_2  = gv_num_2    » Число 2

  IMPORTING

    e_summ   = gv_summ     » Сумма

  EXCEPTIONS

    no_num_1 = 1

    others   = 2.

IF sysubrc <> 0.

MESSAGE ID symsgid TYPE symsgty NUMBER symsgno

            WITH symsgv1 symsgv2 symsgv3 symsgv4.

ENDIF.

WRITE gv_summ.

При запуске программы произойдет вызов исключения, т.к. был использован тип сообщения «Е», программа завершит свое выполнение после показа сообщения:

4

Замечу, что это вовсе не означает, что при вызове ФМ или метода и обработке исключения необходимо завершать работу программы, вы можете свободно продолжить её выполнение и далее, добавив например, сообщение об ошибке в лог программы, а не на вывод как в примере.

Ключевое слово OTHERS используется для того чтобы поймать исключения не описанные в ФМ или явно неуказанные, при вызове ФМ.

Пример вызова неописанного исключения:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

FUNCTION ztest_exc.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH ‘Число 1 не указано, расчёт невозможен’ RAISING no_num_2.

  ENDIF.

  E_SUMM = i_num_1 + i_num_2.

ENDFUNCTION.

В данном примере вызывается неописанное в интерфейсе ФМ исключение – no_num_2, которое будет благополучно поймано с помощью ключевого слова OTHERS (системное поле sy-subrc примет значение равное 2).

Кроме того, можно не обрабатывать большой список всех возможных исключений описанных в ФМ, тогда в случае если такое исключение будет вызвано поле sy-subrc примет значение, указанное в OTHERS.

В ФМ, могут быть добавлены новые исключения и в случае, когда при вызове ФМ они не обработаны и не указано слово OTHERS программа упадет в дамп с ошибкой времени выполнения — RAISE_EXCEPTION. Отсюда вывод, ключевое слово OTHERS подставляем всегда, при вызове ФМ (метода или процедуры), когда мы точно не уверены в неизменности компонента.

5

При вызове исключения в процедурах (perform…) из ФМ, система пытается найти и вызвать исключение в первом ФМ из стека вызовов, если исключение не найдено, вызывается так же, как и неопределенное исключение в ФМ.

Как уже было упомянуто выше, есть возможность получать текст непосредственно из описания особой ситуации:

6

ФМ будет выглядеть следующим образом:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

FUNCTION ztest_exc.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  DATA:

    lv_fun TYPE functfuncname,

    lv_exc TYPE functparameter,

    lv_txt TYPE swotlqshorttext.

  lv_fun = ‘ZTEST_EXC’.

  lv_exc = ‘NO_NUM_1’.

  CALL FUNCTION ‘SWO_TEXT_FUNCTION_EXCEPTION’

    EXPORTING

      language  = sylangu

      function  = lv_fun

      exception = lv_exc

    IMPORTING

      shorttext = lv_txt.

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH lv_txt RAISING no_num_1.

  ENDIF.

  e_summ = i_num_1 + i_num_2.

ENDFUNCTION.

Результат: 7

Иногда особые ситуации используются не как исключения, а как параметры показывающие обработку ФМ и его результат, возвращаемый в поле sy-subrc, хотя лучше бы пренебречь подобным стилем:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

FUNCTION ZMORE_THEN_10.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_VAL) TYPE  I

*»  EXCEPTIONS

*»      MORE_10

*»      LESS_10

*»      EQUAL_10

*»———————————————————————-

  IF i_val = 10.

    RAISE equal_10.

  ELSEIF i_val > 10.

    RAISE more_10.

  ELSE.

    RAISE less_10.

  ENDIF.

ENDFUNCTION.

Программа:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

DATA:

  gv_val TYPE i VALUE 10.

CALL FUNCTION ‘ZMORE_THEN_10’

  EXPORTING

    i_val    = gv_val

  EXCEPTIONS

    more_10  = 1

    less_10  = 2

    equal_10 = 3.

CASE sysubrc.

  WHEN 1.

    WRITE ‘More 10’.

  WHEN 2.

    WRITE ‘Less 10’.

  WHEN 3.

    WRITE ‘Equal

Результат:

8

Сообщения, вызываемые в ФМ или методах, оператором MESSAGE, без дополнения RAISING, либо сообщения вызываемые системой (например, при обработке экранов), могут быть обработаны программой с использованием дополнения: error_message = n_error, указываемого так же после ключевого слова EXCEPTIONS.

При обработке сообщений:

  • Сообщения с типом I, W, S не обрабатываются, но записываются в журнал обработки фонового выполнения, если происходит обработка в фоне.
  • Сообщения с типом E или A могут быть обработаны, при этом в поле sy-subrc будет записано значение n_error. При вызове сообщения с типом А, происходит вызов ROLLBACK WORK (см. описание оператора MESSAGE).
  • Сообщение с типом X не обрабатывается, программа завершается с дампом.

Пример ФМ:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

FUNCTION ztest_exc.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH ‘Число 1 не указано, расчёт невозможен’.

  ENDIF.

  E_SUMM = i_num_1 + i_num_2.

ENDFUNCTION.

Программа:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

PROGRAM test_exceptions.

DATA:

  gv_val TYPE i VALUE 10,

  gv_summ TYPE i.

CALL FUNCTION ‘ZTEST_EXC’

  EXPORTING

    i_num_2  = gv_val    » Число 2

  IMPORTING

    e_summ   = gv_summ    » Сумма

  EXCEPTIONS

    error_message = 1

    others   = 2.

IF sysubrc = 1.

  WRITE ‘ФМ вызвал MESSAGE с типом E,A’.

ENDIF.

Результат:

9

Обработка исключения классическим способом может быть выполнена динамически, с помощью ключевого слова EXCEPTION-TABLE. Пример:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

DATA: line     TYPE c LENGTH 80,

      text_tab LIKE STANDARD TABLE OF line,

      filename TYPE string,

       filetype TYPE c LENGTH 10,

      fleng    TYPE i.

DATA: func TYPE string,

      ptab TYPE abap_func_parmbind_tab,

      ptab_line TYPE abap_func_parmbind,

      etab TYPE abap_func_excpbind_tab,

      etab_line TYPE abap_func_excpbind.

func = ‘GUI_DOWNLOAD’.

filename = ‘c:temptext.txt’.

filetype = ‘ASC’.

ptab_linename = ‘FILENAME’.

ptab_linekind = abap_func_exporting.

GET REFERENCE OF filename INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

ptab_linename = ‘FILETYPE’.

ptab_linekind = abap_func_exporting.

GET REFERENCE OF filetype INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

ptab_linename = ‘DATA_TAB’.

ptab_linekind = abap_func_tables.

GET REFERENCE OF text_tab INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

ptab_linename = ‘FILELENGTH’.

ptab_linekind = abap_func_importing.

GET REFERENCE OF fleng INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

...

etab_linename = ‘OTHERS’.

etab_linevalue = 10.

INSERT etab_line INTO TABLE etab.

CALL FUNCTION func

  PARAMETERTABLE

  ptab

  EXCEPTIONTABLE

  etab.

CASE sysubrc.

  WHEN 1.

    ...

    ...

ENDCASE.

Обработка исключений, основанная на классах

Как понятно из названия, под исключениями в данном случае понимаются объекты специальных классов исключений. Вызов такого исключения может быть выполнен либо в программе с помощью оператора RAISE EXCEPTION, либо системой (например, при делении на ноль будет вызвано предопределённое исключение CX_SY_ZERODIVIDE, список таких исключений), либо через дополнение THROW в условных выражениях (с версии ABAP 7.4).

Во всех случаях инициируется создание объекта указанного класса (если указано дополнение INTO в CATCH), в атрибутах которого содержится информация о возникшей исключительной ситуации, доступ к ним, как правило, осуществляется через методы этого класса.

Классы особых ситуаций могут быть определены как локально, так и глобально через построитель классов – транзакция SE24, диалог создания:

10

В данном случае галочка «с классом сообщений» означает использование в качестве текста сообщения из класса сообщений транзакция SE91 (будет рассмотрено ниже). По умолчанию текст сообщения создается в текстах класса:

11

Категории исключений

Все классы особых ситуаций являются производными одного из классов: CX_NO_CHECK, CX_DYNAMIC_CHECK или CX_STATIC_CHECK, которые сами являются производными общего суперкласса CX_ROOT.

  • CX_STATIC_CHECK – как правило, исключения которые вызываются в процедуре (ФМ или методе), должны быть либо обработаны в ней, либо процедура должна иметь соответствующий интерфейс, чтобы вызывающий её код мог обработать эту ситуацию. Если исключение определено как потомок этого класса, оно должно быть явно указано в интерфейсе метода (ФМ или формы) в котором происходит его вызов. Данная категория используется тогда, когда в коде явно ожидается передача обработки особой ситуации на уровень выше того места где оно было вызвано. Если при статической проверке, система не увидит обработки в блоке TRY..CATCH..ENDTRY подобного исключения система выдаст предупреждение: 12
  • CX_DYNAMIC_CHECK – при проверке кода, компилятор не будет делать предупреждений об отсутствии обработки исключений их этой категории, в случае вызова исключения его обработка будет проверена динамически и если обработчик не будет найден программа упадет в дамп. Обычно данная категория используется тогда, когда исключение может быть обработано внутри самого метода, без передачи обработки выше по стеку. Примером такой категории может являться исключение вызываемое при делении на ноль, передавать его выше по стеку и указывать в интерфейсе метода вовсе не обязательно, т.к. мы можем его обработать внутри самого метода. Однако, если мы хотим передать обработку данного исключения, необходимо указать его в интерфейсе метода.
  • CX_NO_CHECK – аналогичны предыдущему типу, но данную категорию нельзя объявлять в интерфейсах, при этом классы исключений наследуемые от этого класса, неявно все же передаются в интерфейс и выше по стеку вызовов. Данную категорию следует использовать для исключительных ситуаций, которые могут произойти в любое время и не могут быть обработаны непосредственно в коде метода. Кроме того, можно использовать в случаях когда одна и та же исключительная ситуация может возникнуть во множествах методов, а объявлять её в интерфейсах каждого из методов не имеет смысла, т.к. это усложнит код. В итоге подобные исключения могут пройти всю цепочку вызовов методов (т.к. неявно передаются в интерфейс) и быть обработаны на уровне программы.

На исключения накладываются следующие ограничения:

  • Исключение не может быть объявлено в интерфейсе статического конструктора:

13

  • Исключение не может быть объявлено в интерфейсе обработчика событий. При этом если в коде обработчика произошел вызов исключения, и он не был обработан, система вызовет исключение — CX_SY_NO_HANDLER, которое может быть обработано в вызывающем его коде.
  • При вызове программ через SUMBIT или CALL TRANSACTION, исключение, возникающее в вызываемой программе, не может быть передано в вызывающую программу.

Небольшой пример с локальным классом исключения:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

PROGRAM test_exceptions.

CLASS lcx_no_num DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcl_test_exceptions DEFINITION.

  PUBLIC SECTION.

    METHODS:

      do_summ IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING value(re_summ) TYPE int1

              RAISING lcx_no_num.

ENDCLASS.

CLASS lcl_test_exceptions IMPLEMENTATION.

  METHOD do_summ.

    IF i_num_1 IS NOT SUPPLIED OR i_num_2 IS NOT SUPPLIED.

      » Данное исключение присутствует в интерфейсе, может быть обработано вне метода

      RAISE EXCEPTION TYPE lcx_no_num.

    ENDIF.

    TRY.

      re_summ = i_num_1 + i_num_2.

      » Ошибка с дин. проверкой, при её обработке обнулим результат

    CATCH CX_SY_CONVERSION_OVERFLOW.

      re_summ = 0.

    ENDTRY.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test_exceptions TYPE REF TO lcl_test_exceptions,

  gv_summ TYPE int1.

START-OF-SELECTION.

  CREATE OBJECT go_test_exceptions.

  TRY.

    go_test_exceptions>do_summ(

      EXPORTING

        i_num_2 = 1

      RECEIVING

        re_summ = gv_summ

    ).

  CATCH lcx_no_num.

    WRITE ‘Не заполнены все параметры’.

  ENDTRY.

  go_test_exceptions>do_summ(

    EXPORTING

      i_num_1 = 999

      i_num_2 = 1

    RECEIVING

      re_summ = gv_summ

  ).

  WRITE: / ‘Результат cуммы 999 и 1:’, gv_summ.

В стандартной системе SAP имена всех классов особых ситуаций начинаются с CX_ , пользовательские исключения рекомендуется называть, начиная с ZCX или lcx для локальных классов исключений.

Класс CX_ROOT предоставляет некоторые предопределенные методы, которые наследуются всеми классами особых ситуаций:

  • Метод GET_SOURCE_POSITION возвращает имя главной программы и (если связаны) имена включенных программ (инклудов) и номер строки исходного кода, в которой возникла особая ситуация.
  • Метод GET_TEXT возвращает текст особой ситуации в форме строки.
  • Метод GET_LONGTEXT возвращает подробный текст текста особой ситуации в форме строки.

Тексты исключений

Каждому классу можно присвоить несколько текстов. Присвоенные им идентификаторы создаются построителем классов как константы в атрибутах класса. Тексты сохраняются в репозитарии текстов (OTR). Константы идентификаторы, представленные в шестнадцатеричном формате, уникальны на уровне системы:

14

Доступ к хранилищу текстов можно получить через транзакцию SOTR_EDIT.

В текстах можно определить параметры, их необходимо обозначить в амперсандах. В качестве примера, можно рассмотреть текст из класса исключения — CX_SY_FILE_IO:

15

В параметры будут переданы (при вызове метода GET_TEXT) соответствующие им атрибуты класса:

16

Заполняются эти атрибуты в конструкторе при вызове исключения:

DATA: lr_ex  TYPE REF TO cx_sy_file_io,

      lv_msg TYPE string.

TRY.

   ...

   RAISE EXCPETION TYPE cx_sy_file_io

      EXPORTING

         textid = cx_sy_file_io=>read_error

         filename = ‘somefile.txt’.

CATCH cx_sy_file_io INTO lr_ex.

   lv_msg = lr_ex>get_text( ).

   MESSAGE lv_msg TYPE ‘I’.

ENDTRY.

Так же в конструкторе можно указать, какой текст должен использоваться при инициировании особой ситуации, передав одну из определенных констант в параметр импорта TEXTID. Не рекомендуется использовать подобную методику, т.к. это может запутать код, однако как было уже показано выше SAP сам это использует (read_error, write_error в CX_SY_FILE_IO). Инкапсуляция текстов в классах сообщений и их саморасшифровываемость является одним из преимуществ над классическими исключениями.

Конструктор, который генерируется автоматически в SE24, для нового созданного исключения (ZCX_NO_NUM1), выглядит так:

CALL METHOD SUPER>CONSTRUCTOR

EXPORTING

TEXTID = TEXTID

PREVIOUS = PREVIOUS

.

IF textid IS INITIAL.

   me>textid = ZCX_NO_NUM1 .

ENDIF.

Блок обработки исключений

Особая ситуация может быть обработана, только если оператор, который может инициировать ее, заключен в блок TRY-ENDTRY. Затем особая ситуация обрабатывается с помощью оператора CATCH в блоке TRY-ENDTRY.

17

Блок TRY содержит набор операторов, обрабатывающих особые ситуации. Если в блоке TRY появляется особая ситуация, система осуществляет поиск первого оператора CATCH в том же блоке TRY-ENDTRY, а затем последовательно снаружи во всех заключающих блоках TRY-ENDTRY, обрабатывающих особую ситуацию. Если оператор находится, система осуществляет переход к его обработчику. Если обработчик найти не удается, но блок TRY-ENDTRY находится в процедуре, система осуществляет попытку передачи особой ситуации вызывающей программе.

Блок CATCH содержит обработчик особых ситуаций, исполняемый при возникновении указанной особой ситуации в связанном блоке TRY. Для оператора CATCH можно указать любое количество классов особых ситуаций. Таким образом, определяется обработчик особых ситуаций для всех этих классов особых ситуаций и их подклассов.

Блоки TRY-ENDTRY могут иметь вложенность любой глубины. Поэтому блок TRY, блоки CATCH и блок CLEANUP в целом сами могут содержать полные блоки TRY-ENDTRY.

При возникновении особой ситуации система осуществляет поиск по перечисленным обработчикам особых ситуаций в указанном порядке. Затем она исполняет первый обработчик особых ситуаций, оператор CATCH которого содержит подходящий класс особой ситуации или один из ее суперклассов.

Если ошибка не будет обработана и не будет передана вызывающей программе, система выдаст дамп с ошибкой времени выполнения — UNCAUGHT_EXCEPTION, в том случае когда не обрабатывается исключительная ситуация, связанная с ошибкой времени выполнения, система выдает дамп с ошибкой времени выполнения (например, CX_SY_CONVERSION_CODEPAGE — CONVT_CODEPAGE):

18

Просмотр ошибки в транзакции ST22:Безымянный

Распространение особых ситуаций

Если возникает особая ситуация (наследуемая от CX_DYNAMIC_CHECK, CX_STATIC_CHECK), она автоматически распространяется на все уровни стека вызовов, до тех пор, пока она не будет обработана или пока не встретится такой интерфейс, в котором она (либо её предки) будет отсутствовать.

Следующий пример демонстрирует распространение особой ситуации на несколько методов:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

CLASS lcx_calc_error DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcx_summ_error DEFINITION INHERITING FROM lcx_calc_error.

ENDCLASS.

CLASS lcl_test_exc DEFINITION.

  PUBLIC SECTION.

  METHODS:

    do_calc

      RAISING

        lcx_calc_error,

    do_summ

      RAISING

        lcx_summ_error.

ENDCLASS.

CLASS lcl_test_exc IMPLEMENTATION.

  METHOD do_calc.

    do_summ( ).

  ENDMETHOD.

  METHOD do_summ.

    RAISE EXCEPTION TYPE lcx_summ_error.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test TYPE REF TO lcl_test_exc.

START-OF-SELECTION.

  CREATE OBJECT go_test.

  TRY.

    go_test>do_calc( ).

  CATCH lcx_calc_error.

    WRITE ‘Catched’.

  ENDTRY.

Обратите внимание на метод do_calc, в нем описана особая ситуация от которой наследуется lcx_summ_error, соответственно прерывание продолжится на следующий уровень и будет обработано в блоке TRY..CATCH..ENDTRY. При правильно выстроенной архитектуре наследования исключительных ситуаций, прозрачность кода заметно повышается.

В случае, когда используется исключение, наследуемое от CX_NO_CHECK, описание его в интерфейсе метода может быть опущено, т.к. оно инициируется неявным способом системой:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

CLASS lcx_calc_error DEFINITION INHERITING FROM cx_no_check.

ENDCLASS.

CLASS lcx_summ_error DEFINITION INHERITING FROM lcx_calc_error.

ENDCLASS.

CLASS lcl_test_exc DEFINITION.

  PUBLIC SECTION.

  METHODS:

    do_calc,

    do_summ.

ENDCLASS.

CLASS lcl_test_exc IMPLEMENTATION.

  METHOD do_calc.

    do_summ( ).

  ENDMETHOD.

  METHOD do_summ.

    RAISE EXCEPTION TYPE lcx_summ_error.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test TYPE REF TO lcl_test_exc.

START-OF-SELECTION.

  CREATE OBJECT go_test.

  TRY.

    go_test>do_calc( ).

  CATCH lcx_calc_error.

    WRITE ‘Catched’.

  ENDTRY.

Очистка после вызовов исключений

Блок CLEANUP исполняется, когда выполнен выход из блока TRY-ENDTRY, так как система не смогла найти обработчик для исключения в определенном блоке TRY-ENDTRY, но особая ситуация обрабатывается в окружающем блоке TRY-ENDTRY или передается вызывающей программе.

Данный блок обычно применяется для освобождения занятых ресурсов: очистке ссылочных переменных, закрытие локаторов или наборов данных (datasets) и т.п. Допустим, Вы записываете некоторые данные в файл на сервере приложений. Внутри блока TRY Вы открываете набор данных (dataset) и начинаете запись в него. Однако в некоторый момент, случается особая ситуация, которую вы не обработали и блок TRY прерывает свою работу, при этом, не выполнив закрытие набора данных. Для того чтобы избежать подобной ситуации воспользуемся ключевым словом CLEANUP:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

TRY.

*  Открываем файл на запись:

   OPEN DATASET lv_file FOR OUTPUT IN TEXT MODE

                        ENCODING DEFAULT.

*  Переносим данные в файл:

   LOOP AT lt_extract INTO ls_record.

      PERFORM sub_format_record CHANGING ls_record.

      TRANSFER ls_record TO lv_file.

   ENDLOOP.

*  Закрываем файл:

   CLOSE DATASET lv_file.

CATCH cx_sy_file_access_error INTO lr_file_ex.

*  Ошибки ввода, вывода (датасет в таком случае не открыт)…

CATCH lcx_format_error INTO lr_format_ex.

*  Обрабатываем свою внутренюю ошибку при форматировании…

*  при этом необходимо закрыть набор данных

   CLOSE DATASET lv_file.

CLEANUP.

*  В случае если возникнет не обработанное исключение закроем набор данных:

   CLOSE DATASET lv_file.

ENDTRY.

В случае возобновляемых оператором RESUME исключений, блок CLEANUP не выполняется. Блок CLEANUP, как и блок CATCH позволяет получить ссылочную переменную на вызванное исключение, с помощью дополнения [INTO oref].

Передача исключений по цепочке

Необходимо понимать, что особая ситуация может передаваться через любое количество иерархий вызова перед финальной обработкой. Одна особая ситуация может инициировать вторую и т. д. Каждая инстанция должна оставаться действительной, независимо то того, был ли связанный блок CATCH уже обработан или нет. Поэтому необходимо убедиться, что предыдущая инстанция особой ситуации доступна с помощью, по крайней мере, одной ссылки. Атрибут общей инстанции PREVIOUS, наследуемый всеми классами особых состояний из CX_ROOT, обеспечивает удобный для этого способ.

Пример:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

CLASS lcx_very_big DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcx_calc_error DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcl_test_exceptions DEFINITION.

  PUBLIC SECTION.

    METHODS:

      do_calc IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING VALUE(re_result) TYPE i

              RAISING lcx_calc_error.

  PRIVATE SECTION.

    METHODS:

      do_summ IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING value(re_summ) TYPE i

              RAISING lcx_very_big.

ENDCLASS.

CLASS lcl_test_exceptions IMPLEMENTATION.

  METHOD do_summ.

    re_summ = i_num_1 + i_num_2.

    IF re_summ > 100.

      RAISE EXCEPTION TYPE lcx_very_big.

    ENDIF.

  ENDMETHOD.

  METHOD do_calc.

    DATA:

      lo_very_big TYPE REF TO lcx_very_big.

    TRY.

      me>do_summ(

        EXPORTING

          i_num_1 = i_num_1

          i_num_2 = i_num_2

        RECEIVING

          re_summ = re_result

      ).

    CATCH lcx_very_big INTO lo_very_big.

      RAISE EXCEPTION TYPE lcx_calc_error EXPORTING previous = lo_very_big.

    ENDTRY.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test_exceptions TYPE REF TO lcl_test_exceptions,

  gv_result TYPE i,

  go_calc_error TYPE REF TO lcx_calc_error,

  go_big_error  TYPE REF TO lcx_very_big.

START-OF-SELECTION.

  CREATE OBJECT go_test_exceptions.

  TRY.

    go_test_exceptions>do_calc(

      EXPORTING

        i_num_1   = 1000

        i_num_2   = 500

      RECEIVING

        re_result = gv_result

    ).

  CATCH lcx_calc_error INTO go_calc_error.

    go_big_error ?= go_calc_error>previous.

  ENDTRY.

Таким образом, пройдя по цепочке, мы всегда можем определить, в каком конкретном месте было инициировано исключение и что из-за этого произошло. Иногда при построении какой-либо ООП модели, удобно собрать всю цепочку из ошибок в каком-нибудь одном виде и выдать в качестве универсального исключения, в качестве примера рекомендую посмотреть этот пример.

Возобновляемые исключения и повтор блока TRY

При срабатывании исключения, выполнение программы в текущем контексте завершается. Иногда необходимо не завершать выполнение текущего контекста, для этого были созданы так называемые возобновляемые исключения. Для того чтобы вызвать такое исключение, необходимо в операторе RAISE (или в THROW) указать что вызывается именно возобновляемое исключение, при этом для того чтобы воспользоваться оператором RESUME (который возвращает код обратно в то место где было вызвано исключение), необходимо у оператора CATCH указать дополнение BEFORE UNWIND (обозначает обработку возобновляемого исключения), иначе система вызовет исключение CX_SY_ILLEGAL_HANDLER. При возврате в контекст, из которого было вызвано исключение блок CLEANUP не вызывается. Если в указанном в CATCH блоке не будет вызван оператор RESUME, контекст будет удален при выходе из блока CATCH.

Пример обработки возобновляемого исключения:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

CLASS lcx_no_num DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcx_less_zero DEFINITION INHERITING FROM cx_no_check.

ENDCLASS.

CLASS lcl_test_exceptions DEFINITION.

  PUBLIC SECTION.

    METHODS:

      do_summ IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING value(re_summ) TYPE int1

              RAISING RESUMABLE(lcx_no_num).

ENDCLASS.

CLASS lcl_test_exceptions IMPLEMENTATION.

  METHOD do_summ.

    IF i_num_1 IS NOT SUPPLIED OR i_num_2 IS NOT SUPPLIED.

      » Данное исключение присутствует в интерфейсе, может быть обработано вне метода

      RAISE RESUMABLE EXCEPTION TYPE lcx_no_num.

    ENDIF.

    TRY.

      re_summ = i_num_1 + i_num_2.

      » Динамическая ошибка, при её обработке обнулим результат

    CATCH CX_SY_CONVERSION_OVERFLOW.

      re_summ = 0.

    ENDTRY.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test_exceptions TYPE REF TO lcl_test_exceptions,

  gv_summ TYPE int1.

START-OF-SELECTION.

  CREATE OBJECT go_test_exceptions.

  TRY.

    go_test_exceptions>do_summ(

      EXPORTING

        i_num_2 = 1

      RECEIVING

        re_summ = gv_summ

    ).

  CATCH BEFORE UNWIND lcx_no_num.

    RESUME.

  ENDTRY.

  WRITE: / ‘Cумма без указания 1-го числа’, gv_summ.

  go_test_exceptions>do_summ(

    EXPORTING

      i_num_1 = 999

      i_num_2 = 1

    RECEIVING

      re_summ = gv_summ

  ).

  WRITE: / ‘Результат cуммы 999 и 1:’, gv_summ.

При обработке исключений так же есть возможность повтора блока TRY..CATCH, делается это с использованием оператора RETRY. Пример:

PARAMETERS: number1 TYPE i,

            number2 TYPE i.

DATA result  TYPE p DECIMALS 2.

TRY.

    result = number1 / number2.

  CATCH cx_sy_zerodivide.

    number1 = 0.

    RETRY.

ENDTRY.

В данном случае если номер 2 будет равен нулю, система вызовет исключение, с помощью RETRY мы заново запустим блок TRY..CACTH, при этом уже исключение не возникнет, т.к. при делении нуля на ноль результатом будет ноль.

Отображение сообщений из классов сообщений в тексты исключений

Начиная с версии 6.40, появилась возможность связывать тексты исключительных сообщений с классами сообщений (транзакция SE91). Как уже упоминалось выше для этого необходимо в конструкторе класса, указать галочку класс сообщений. При этом вместо интерфейса IF_MESSAGE будет внедрен интерфейс IF_T100_MESSAGE (таблица T100 хранит в себе эти сообщения):

19

При редактировании текста, необходимо будет привязать его к классу и номеру сообщения, при этом заполнить параметры, если это необходимо:

20

Начиная с NW 2004, оператор MESSAGE позволяет напрямую обработку исключений, внедряющих интерфейс IF_T100_MESSAGE:

TRY.

   ...

CATCH cx_some_exception INTO lr_ex.

   MESSAGE lr_ex TYPE ‘E’.

ENDTRY.

Локальный класс исключения в приватном методе глобального класса

Бывают ситуации, когда для какого-либо приватного метода необходимо реализовать исключение, которое может быть вызвано исключительно данным методом (классом).  Реализовать подобное можно, если создать локальный класс исключений:

  • Перейти в локальные определения/внедрения:

21

  • Создать класс исключения:

22

  •  Указать в методе имя локального класса исключения (обязательно в режиме редактирования исходного кода):

23

Результат:

24

Если попробовать сделать тоже самое в режиме редактирования на основе формуляров, выскочит предупреждение о том, что такого класса не существует:

25

Более подробно об исключениях можно почитать в официальной документации:

http://help.sap.com/abapdocu_740/en/abenabap_exceptions.htm

ABAP Managed Database Procedures (AMDP) — новая технология встраивания собственного исходного текста базы данных в приложения на ABAP. Благодаря появлению и развитию SAP HANA разработчики на ABAP теперь могут использовать функции базы данных, превышающие возможности Open SQL. AMDP доступны в SAP NetWeaver 7.40 с пакетом поддержки 5 , но для применения некоторых описанных здесь функций требуются следующие пакеты поддержки.

Ключевое понятие

Технология ABAP Managed Database Procedures позволяет встроить выполнение команд языка базы данных в язык ABAP и среду разработки ABAP. При этом проводятся проверки синтаксиса и анализ динамических ошибок, а также обеспечивается управление жизненным циклом.

Большинство разработчиков ABAP столкнулись с необходимостью иметь доступ к базе данных, используя родной язык запросов, реализуемый системой управления базой данных. Например, для того, чтобы воспользоваться функциями управления базой данных, которые не входят в объем Open SQL, или оптимизировать код формируемых запросов для конкретной базы данных.

Теперь благодаря технологии ABAP Managed Database Procedures (AMDP) у них появилась возможность применять к базе данных более сложную прикладную логику. В отличие от более ранних решений, здесь это можно выполнить в рамках хорошо структурированного и четкого подхода.

В этой статье AMDP рассматривается с использованием стандартной среды разработки ABAP. Здесь описано синтаксическое встраивание и взаимодействие между сервером приложений ABAP и системой управления базой данных (СУБД). Такая информация поможет разработчикам понять, почему и в каких случаях возникают те или иные синтаксические или динамические ошибки.

Мы рассмотрим устранение связанных с базой данных проблем с помощью знакомых вам инструментов ABAP 9например, отладчика ABAP и анализа динамических ошибок ABAP), а также перечислим возможности расширения и особенности интеграции в структуру Business Add-In (BAdI).

Однако сначала сравним предыдущие возможности с новой функциональностью AMDP.

Прежде и теперь

Кратко вспомним прежние возможности для прямого доступа к базе данных через ABAP.

EXEC SQL

С «доисторических» времен ABAP — или с того периода, который многие современные разработчики назовут «доисторическим» — технология EXEC SQL существовала как способ вставки блока исходного текста на языке управления базой данных в ABAP. Блок EXEC SQL представляет собой всего лишь контейнер для любого языка управления базой данных с исходным текстом внутри. Этот текст, как надеется разработчик, будет распознан и корректно выполнен соответствующей СУБД. В большей или меньшей степени игнорируемые компилятором ABAP, эти фрагменты кода переносятся через системный ландшафт вместе с кодом ABAP. Во время выполнения они отправляются в базу данных для обработки.

Этот самый базовый подход не предполагает большого удобства в отношении таких важных вещей, как синтаксические проверки или анализ динамических ошибок. Чтобы выполнить тщательную проверку синтаксиса, разработчику потребуется дополнительная среда разработки для работы с базой данных. В противном случае придется воспользоваться старым добрым методом проб и ошибок. Работа с динамическими ошибками не идет дальше поиска сообщений об ошибках SQL.

ABAP Database Connectivity (ADBC)

Технология ADBC, появившаяся как альтернатива EXEC SQL, является полностью динамическим методом. Это система на основе классов, которая позволяет повторно использовать вызываемый код доступа к базе данных и применять к нему модульное проектирование. Ошибки возвращаются в виде исключений, которые проще обработать. Обмен данными между сервером приложений ABAP (AS ABAP) и базой данных осуществляется более универсальным способом, чем в EXEC SQL, где использование переменных было ограничено плоскими структурами и элементарными полями.

Несмотря на то, что технология ADBC отличается скоростью и удобством для вызова отдельных команд базы данных, на более длинных текстах исходного кода проявляется ее некоторая громоздкость, что, несомненно, проявится в том случае, если ABAP приложения передают большие фрагменты своего кода на выполнение в базу данных. Тем не менее, ADBC позволяет проводит синтаксические проверки встроенного исходного текста, что очень важно для обеспечения его качества.

CALL DATABASE PROCEDURE

Для компенсации недостатков EXEC SQL и ABDC, в частности, отсутствия статических проверок, команда CALL DATABASE PROCEDURE работает с исходным текстом, который контролируется не средой ABAP (AS ABAP), а непосредственно базой данных (SAP HANA). Соединение между SAP HANA и репозитарием ABAP устанавливается через прокси процедуры.

Результатом является прямое управление жизненным циклом разработки для более эффективной проверки синтаксиса. Разработчикам и администраторам приходится решать задачи синхронизации переносов такого кода в среде разработки ABAP и SAP HANA.

Можно ли улучшить этот процесс?

Да, можно. AMDP возвращается к концепции встраивания исходного текста родных команд управления базой данных в код ABAP, как и в EXEC SQL, но на этот раз со всеми неотъемлемыми удобствами ABAP: выделением синтаксиса, тщательной синтаксической проверкой, автодополнением и навигацией по исходному тексту. И что важнее всего, управление жизненным циклом разработки осуществляется AS ABAP. Как оказалось, это весьма существенно.

Основная идея AMDP заключается в использовании специальных методов ABAP в качестве контейнеров для исходного текста родных команд базы данных. Это означает, что для реализации метода имеются дополнения, указывающие систему базы данных и язык исходного текста.

Во время выполнения разработчики ожидают, что исходный текст будет доступен и исполним в базе данных без дополнительных процедур. В случае сбоя вызова им хотелось бы получать осмысленные сообщения об ошибках. Кроме того, к списку желаний здесь можно добавить поддержку при отладке и расширяемость.

Посмотрим, выполняет ли AMDP эти требования.

Создание метода AMDP

В следующих разделах статьи описан жизненный цикл методов AMDP, начиная с первого примера реализации на рис. 1.

Рис. 1. Реализация метода AMDP

Этот метод не содержит ABAP-кода, но строки между METHOD и ENDMETHOD являются исходным текстом текстом на языке используемой базы данных. В отличие от EXEC SQL, оператор метода обогащен синтаксическими добавлениями для указания базы данных (в данном случае HDB, т.е. SAP HANA) и указания используемого языка базы данных (здесь SQLSCRIPT). Это база для выделения синтаксиса и выполнения подробной синтаксической проверки.

Инфраструктура AMDP подготовлена для поддержки различных платформ и языков управления базами данных. Сегодня всеобщее внимание устремлено на SAP HANA, а реализация осуществляется только на базе SAP HANA с языком базы данных SQLScript. На рис. 2 показан часть класса AMDP с определением.

Рис. 2. Определение класса AMDP

В верхней части определения класса отображается интерфейс с именем IF_AMDP_MARKER_HDB. Этот интерфейс является обязательным и помечает класс как класс, содержащий методы AMDP (для HDB). Такой класс называется классом AMDP. Он также может содержать методы ABAP. В удобном интерфейсе несложно найти все классы AMDP, находящиеся в системе.

Сигнатура метода AMDP не отличается от метода ABAP. По сути, с первого взгляда читатель даже не поймет, что метод реализован как метод вызова в терминах родного языка базы данных. Однако, как мы узнаем ниже, в отношении параметров метода применяется ряд ограничений.

Методы AMDP могут являться статическими методами или методами экземпляра класса, общедоступными (Public) или частными (Private). Решение о выборе типа метода принимается в зависимости от структуры программного обеспечения или согласно личным предпочтениям разработчика.

Перенос данных между ABAP и базой данных с помощью методов AMDP

Поскольку методы AMDP встраиваются в приложения ABAP, они обязательно взаимодействуют с данными ABAP. С одной стороны, процедуры базы данных оперируют таблицами, ракурсами или объектами базы данных в целом. В теле метода разработчики должны иметь возможность обращаться к этим объектам.

Параметры

Методы AMDP могут иметь параметры EXPORTING, IMPORTING и CHANGING, но не RETURNING. Последний используется только в функциях базы данных AMDP, которые представляют собой вариант методов AMDP, описанных ниже.

Как было видно на предыдущем примере фрагмента кода (рис. 2), сигнатура метода AMDP выглядит как сигнатура метода ABAP с параметрами на основе типов данных ABAP. Несмотря на то, что тело реализовано на другом языке с другими типами системы, разработчикам не стоит беспокоиться о том, что в результате преобразования данных между языками возникнет масса ошибок. Система AMDP гарантирует корректное преобразование соответствующих типов базы данных в типы языка ABAP.

AMDP поддерживает элементарные типы ABAP и внутренние структурные типы, что упрощает обработку параметров, которая всегда была достаточно трудоемкой задачей в EXEC SQL или ADBC. Внутренние таблицы могут содержать вложенные структуры, поскольку создать аналог для глубоких структур в базе данных невозможно.

При импорте параметров возможно использование значений по умолчанию, которые устанавливаются в сигнатуре метода. Здесь AMDP также преобразует значения по умолчанию согласно системе соответствия типов из базы данных.

Единственным ограничением в отношении параметров метода AMDP является обязательный вызов по значению. Это очевидно, поскольку вызов метода AMDP означает выход из стека ABAP. Как при выполнении Remote Function Call (RFC), вызываемая сторона (в данном случае база данных) не получает доступа к данным ABAP.

Использование объектов ABAP-словаря

В теле метода AMDP разработчикам может потребоваться обратиться к другим объектам базы данных: таблицам и объектам в схеме базы данных (далее — схема SAPSID), а также к таблицам в других схемах, не относящихся к текущему AS ABAP.

Управление большей частью объектов базы данных в схеме SAPSID осуществляет ABAP-словарь. Таким образом, инфраструктура AMDP может проверять их наличие, табличные структуры и версии. Она позволяет выявить возможные синтаксические ошибки на очень ранних этапах проверки для любого типа базы данных. Вы можете воспользоваться преимуществами, которые дает такая информация, и получить максимально эффективные сообщения синтаксической проверки и средства навигации по исходному тексту. Таким образом, метод AMDP содержит описание USING, которое перечисляет таблицы, ракурсы или объекты базы данных, используемые в методе и хранящиеся в схеме SAPSID (рис. 3).

Рис. 3. Объявление таблиц словаря данных со ссылкой в условии USING

Дважды щелкните по любому объекту в списке USING для перехода к определению данных (например, транзакция SE11).

Объекты базы данных для схем, отличных от SAPSID, ABAP-словарем не контролируются, поэтому AMDP приходится полагаться на то, что они существуют и являются корректными. Указывать их в условии USING не обязательно, но обращаться к ним необходимо посредством префикса схемы.

Наконец, методы AMDP могут вызывать другие методы AMDP (рис. 4). Поскольку сами методы AMDP являются управляемыми ABAP объектами, они должны быть указаны в условии USING с полным именем.

Рис. 4. Объявление другого метода AMDP, вызванного в теле метода AMDP в условии USING

Синтаксическая проверка

Оформите подписку sappro и получите полный доступ к материалам SAPPRO

Оформить подписку

У вас уже есть подписка?

Войти

Предисловие — Этот пост является частью ABAP-новичок серии.

Введение

Всякий раз, когда кодер SAP пишет программу. Если во время выполнения он выдает дамп или ошибку времени выполнения, то отладчик SAP — это инструмент для проверки ваших строк кода и изучения ошибок во время выполнения. Отладка в SAP ABAP помогает программисту проверять поток своей программы во время выполнения.

МЫ ИСПОЛЬЗУЕМ ABAP-отладчик по умолчанию после выпуска SAP 7.0.

Определение

Короче говоря, мы можем определить как:

  • Инструмент для анализа программ ABAP.
  • Инструмент для проверки ошибок в коде во время выполнения.
  • Инструмент для отображения объектов данных.
  • Инструмент для понимания логики потока кодов в программе во время выполнения.

Пошаговое выполнение программы с помощью отладчика помогает обнаруживать и исправлять ошибки в исходном коде программы ABAP.

Что такое Бточка возгорания?

Сигнал, сообщающий исполняющему процессору о необходимости прервать обработку и начать отладку.

Он активируется, когда программа достигает этой точки.

Как мы можем отлаживать

Установив точку останова

Запустите отладчик, установив и управляя точками останова и выполнив код.

Запустив режим отладки программы

Мы можем войти в режим отладки, используя h с любого экрана.

Это можно сделать, когда мы хотим проверить программу с самого начала и не знакомы с программой.

Типы точек останова

Существует два типа точек останова:

А. Статическая точка останова

  1. Эта точка останова не относится к пользователю.
  2. Чтобы использовать статическую точку останова, используйте ключевое слово ABAP. ТОЧКА РАЗЛОМА.
  3. Поместите его в строку, где вы хотите использовать точку останова.

Пример:

ПРОГРАММА Z_USERDATA.

…..если sy-subrc<>0 .

ТОЧКА РАЗЛОМА.

конец

….

  1. Если вы хотите установить статическую точку останова для конкретного пользователя.

BREAK-POINT имя пользователя.

ПРИМЕЧАНИЕ:

Пожалуйста, удалите статические точки останова вручную в самой системе разработки, иначе это может повлиять на программу в производственной системе.

B. ДИНАМИЧЕСКАЯ ТОЧКА ИЗЛОМА

  1. Это точки останова, которые запускаются, когда выполняемая вами программа достигает определенного оператора ABAP или класса исключений..
  2. Когда сеанс отладки завершен, он автоматически удаляется.
  3. Вы можете установить динамическую точку останова либо в редакторе ABAP, либо непосредственно в отладчике.

с.1. Для установки динамических точек останова в редакторе ABAP.

c.1.1 Поместите курсор на строку исходного кода, где вы хотите установить точку останова.

в.1.2. Перейдите в утилиты->точка останова->Установить/Остановить. Система подтверждает, что точка останова установлена.

в.2. Для установки динамической точки останова в режиме отладки:

c.2.1- Поместите курсор на строку, где вы хотите установить точку останова.

c.2.2- Выберите строку, дважды щелкнув по ней или выбрав Точка останова-> установить/удалить.

ПРИМЕЧАНИЕ:  Пользователь может установить 30 динамических точек останова без изменения кода программы..

  1. Точка останова сеанса
    Индивидуально для конкретного сеанса пользователя ABAP. Если сеанс пользователя завершается (выход из системы SAP), все точки останова сеанса удаляются.
  2. Внешняя точка останова
    Они применяются к текущему сеансу пользователя, а также к будущим сеансам пользователя.

д.1. Работает в сеансах, инициированных запросами RFC или HTTP или любым другим внешним интерфейсом.

д.2. Внешняя точка останова может применяться к:

e.2.1.Пользователь в текущей системе SAP

д.2.2. Пользователь на текущем сервере приложений текущей системы SAP

д.2.3. Сеансы пользователей начинаются по запросу, который имеет определенный идентификатор терминала.

ПРИМЕЧАНИЕ:  Сессия, внешние точки останова могут быть созданы во время выполнения и могут быть активированы/деактивированы.

Специальные КЛЮЧИ в отладке

Отладка в SAP ABAP — иллюстрация изображения

Отладка в SAP ABAP — иллюстрация изображения

F5- выполняет программу построчно.

F6- Выполняет функциональный модуль или подпрограмму без входа в нее.

F7- выполняет модуль или программу за один шаг.

F8 — запускает программу напрямую. Если имеется более одной точки останова, то можно перейти от одной точки останова к другой.

Глава 5: Динамические программы

Содержание

Эта глава покажет структуру более сложных программ с интегрированными экранами. Вы создадите новую программу, которая выбирает и показывает сведения о, об одном из авиарейсов из базы данных SAP. Здесь вы воспользуетесь технологией dynpro (экранов).

Обоснование

Так как большая часть транзакций SAP все еще разрабатывается на ABAP и dynpro, эта глава является одной из наиболее важных для понимания логики SAP.

Требования

Вы должны уметь пользоваться словарем ABAP и SQL-запросам.

41

Задание 1: Вход в систему SAP

Краткое описание: Используя SAPGui, войдите в систему с вашим именем пользователя и паролем

Запустите SAPGui и войдите в систему, используя предоставленное имя пользователя и пароль. Вы можете найти их в главе 1.

Задание 2: Создание первой программы с несколькими экранами (dynpros)

Краткое описание: Создайте программу, которая использует 2 экрана, чтобы отобразить сведения об авиарейсе из базы SAP

Запустите Навигатор по объектам из меню SAP Easy Access, используя следующий путь:

Инструменты ABAP-инструментальные средства Обзор • Навигатор по объектам.

Код данной транзакции – SE80

Создайте новую программу «ZY_*##_DYNPRO». Поставьте галочку «с TOP INCL.».

Измените название TOP-include на «ZY_*##_DYNPRO_TOP‟.

Совет:

Заметьте, что система SAP автоматически предложила имя для top include, которое не начиналось с обязательной буквы Z, обозначающей клиентский top include. В будущем, во время разработки вы часто будете сталкиваться с ситуацией, когда система предлагает название не из клиентского пространства имен. Будьте внимательны!

В следующем окне вы видите все свойства программы. Выберите статус «Тестовая» и Приложение «Общее для всех приложений». Нажмите «Enter», затем присвойте программу пакету «ZY_*##» и своему транспортному запросу. Система дважды спрашивает запрос переноса, так как первый относится к программе, а второй к top include.

Откройте top include, дважды щелкнув на нем. На этом шаге вы должны определить все глобальные переменные. Такие переменные доступны для всей программы и каждый экран имеет доступ к ним. Такими переменными будут таблица SPFLI,

42

системная переменная ok_code и рабочая переменная wa_flight. Определите их в the top include:

Следующий шаг – создание первого экрана (dynpro). Нажмите правой клавишей мыши по названию программы в дереве навигации и создайте новый экран с номером 100.

Теперь вы должны определить свойства нового экрана. Введите описание, а также экран «200» в качестве «Следующего экрана». Это позволит программе перейти к экрану 200 после того, как PAI-модуль 100-го экрана будет выполнен. Да, вы еще не создали экран 200, но вы сделаете это позже.

43

На следующем шаге вы создадите внешний вид экрана. Для этого запустите редактор

экранов, нажав включен, вы не кнопку «Назад»

кнопку на панели инструментов. Пока редактор экранов можете пользоваться SAPGui. Вы можете вернуться в SAPGui, нажав в редакторе экранов.

Нажмите кнопку текстового поля и нарисуйте текстовое поле на экране. Назовите его «TXT_INSTRUCTION» и введите текст: «Пожалуйста, выберите авиакомпанию и номер рейса». Экран должен выглядеть следующим образом:

Пользователь программы должен выбрать авиакомпанию и номер рейса на данном экране. Эта информация хранится в таблице SPFLI. Чтобы создать два поля ввода со справкой по значениям вы должны сослаться на таблице SPFLI из словаря данных.

Сделать это очень легко нажав кнопку «Окно словаря/полей программы» на панели инструментов. Введите название SPFLI и нажмите «Вызвать из словаря».

Так как ваше приложение должно предоставлять пользователю 2 поля ввода для авиакомпании и для рейса, выберите строки «CARRID» и «CONNID» и нажмите Enter. Это действие изменит внешний вид курсора и позволит разместить два поля ввода на экране. Экран должен получить следующий вид:

44

На следующем шаге нужно добавить кнопку перехода на второй экран. Добавьте кнопку и назовите ее «BTN_SELECT», текст на кнопке выберите сами. После ввода информации вы заметите, что кнопка все еще подсвечена красным. Это означает, что системе недостаточно предоставленной информации.

Совет:

Если элемент в редактор экранов подсвечен красным, это означает, что для корректной работы требуются дополнительные данные. Дважды щелкнув по элементу, можно получить справку по данной конкретной проблеме.

Так как новая кнопка все еще подсвечена красным, вам необходимо ввести код функции. Дважды щелкните по кнопке. Это действие откроет свойства, где будет одно красное поле ввода, куда нужно ввести код функции («КодФкц») «SELECT» и нажать enter. Позже в программе нажатие кнопки должно будет автоматически присваивать переменной «ok_code» значение «SELECT». Эта переменная доступна из всех модулей программы, так как была объявлена в top include. Но пока что связь между кодом функции и переменной «ok_code» отсутствует. Чтобы добавить эту связь,

нажмите кнопку «Окно списка элементов» на панели инструментов. Откроется окно со списком элементов редактируемого экрана.

Вновь вы видите красное поле, показывающее, что чего-то не хватает. Рядом с красным полем есть маленький OK-символ, представляющий переменную «ok_code». Введите «OK_CODE», чтобы создать связь с глобальной переменной «ok_code».

Сохраните экран и вернитесь в навигатор по объектам. Чтобы упростить использование программы, создайте для нее код транзакции. Нажмите правой кнопкой мыши по названию программы в дереве навигации и выберите:

Создать Транзакция:

45

Заметьте, что транзакция пока никак не связана с вызываемой программой. Связь между кодом транзакции и программой будет настроена позже в свойствах транзакции. Это значит, что вы можете вызывать программу с названием, отличающимся от кода транзакции. Например, навигатор по объектам вызывается кодом SE80.

В свойствах транзакции вы можете определить вызываемую программу. Введите название «ZY_*##_DYNPRO» и номер экрана 100. Проверьте и сохраните

46

транзакцию, активируйте все ваши разработки, если они все еще не были активированы.

Чтобы протестировать программу, откройте новый режим и вызовите программу, используя код транзакции. Вы увидите текст и два поля ввода. Первое поле снабжено справкой по значению, а второе нет. При нажатии созданной кнопки, вы увидите ошибку ABAP. Это логично, ведь вы определили следующим экраном экран 200, а его все еще не существует.

Вернитесь в программу и переключитесь на вкладку «Логика выполнения». Здесь отображается логика выполнения первого экрана, разделенная на этапы «до вывода» и «после ввода». Добавьте следующий код:

Почему этот код важен, можно показать очень легко в программе. Запустите программу еще раз и протестируйте ее поведение. Вы заметите, что оба поля ввода имеют справку по значению. Вторая справка формируется на основе того, что введено в первое поле и показывает только рейсы, выполняемые выбранной авиакомпанией.

Прежде чем закончить логику выполнения, разберемся со строкой состояния и названием программы. Для этого уберите значок комментария около строки «MODULE STATUS_0100» в логике выполнения и дважды нажмите на «STATUS_0100». Появится вопрос, хотите ли вы создать новый модуль. Выберите

«Да».

Система автоматически предложит название для нового модуля. Название для PBOмодуля нам подходит, а название нового include нет. Добавьте «ZY_» в начало названия нового include. Нажав Enter, вы увидите сообщение о том, что дополнительный include появился в программе.

Это логично, так как вы создаете новый include для строки состояния, и он должен быть включен в программу. Дважды нажмите на модуль STATUS_0100, чтобы перейти к его исходному коду.

47

Раскомментируйте обе строки SET и замените «xxx» на номер «100». Теперь вы настроите панель статуса и строку заголовка для вашего экрана. Для этого дважды щелкните на цифру «100» после «PF-STATUS». Система спросит, хотите ли вы создать статус. Ответьте «Да» и введите краткое описание на следующем экране. После появится следующее окно:

Здесь вы можете создавать, редактировать и удалять панель статуса своего экрана. Вы можете изменить код, передаваемый каждой кнопкой программе. Кнопки, которым никакой код не присвоен, впоследствии будут недоступны. Настройте кнопку «Назад», добавив текст «BACK» в соответствующее поле. Сохраните панель статуса и вернитесь к коду программу. Дважды щелкните на «100» после «TITLEBAR».

48

Заполните строку заголовка. Сохраните и активируйте все созданные объекты и протестируйте программу. Она должна выглядеть схожим образом:

Теперь закончим логику выполнения. Перейдите к экрану «100» на вкладку «ЛогикаВыполн.». Раскомментируйте строку «USER_COMMAND_0100» и дважды щелкните по ней. Вам будет задан вопрос, хотите ли вы создать объект. Ответьте «Да» и исправьте название include: удалите последние 3 знака названия и добавьте «ZY_» в начало.

Присвойте новый модуль своему пакету. На следующем шаге вы должны добавить логику выполнения в этот модуль. В зависимости от значения «ok_code» программа должна либо прекращать свою работу («BACK») либо считывать данные из таблицы SPFLI SELECT»). Добавьте инструкцию «CASE»:

49

Сохраните, проверьте и активируйте все свои объекты.

Совет:

Заметьте, что инструкция CASE чувствительна к регистру. Это означает, что «back» и «BACK» отличаются при использовании в инструкции CASE! Это довольно распространенная ошибка.

Задание 3: Создание второго экрана

Краткое описание: Создайте второй экран, чтобы отобразить сведения о рейсе.

Вы создали первый экран, чтобы пользователь мог выбрать авиарейс, но теперь нужен второй, чтобы вывести туда сведения о нем.

Создайте экран с номером «200». Посмотрите задание 2, если не помните, как это делается. Установите экран «100» «следующим экраном».

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

Что тут нужно сделать?

Категория Внутренняя ошибка ядра
ДинамОшибка DDIC_TYPE_INCONSISTENCY
Прикладной компонент BC-ABA-LA
Дата и время 03.07.2013 18:04:43

Краткий текст
Inconsistency in the dictionary for the structure «COEP_ONLY».

Что произошло?
Error in the SAP kernel.

The current ABAP «ZBPC_EKP_R» program had to be terminated because the
ABAP processor detected an internal system error.

Что Вы можете сделать?
Note which actions and input led to the error.

For further help in handling the problem, contact your SAP administrator
.

You can use the ABAP dump analysis transaction ST22 to view and manage
termination messages, in particular for long term reference.

Анализ ошибки
There is an internal system error.
eliminated with ABAP/4.

There is an inconsisteny for the DDIC structure «COEP_ONLY», the corresponding
Dictionary runtime object (NAMETAB) is incorrect.

The number of components of the structure (NAMETAB component «fldcnt»)
is specified as 77. If all the substructures are resolved and the
actual total number of components is calculated recursively, a different
value is returned.

Указания по устранению ошибки
The error was probably caused by changes being made to the
DDIC structure «COEP_ONLY» or one of its substructures and an error occurred
afterwards at activation. Check the runtime object of the structure «COEP_ONLY»
in the Dictionary to analyze the exact cause of the error.

If the program RSNTABCONSISTENCY or its predecessor RSDDCHECK exists in
your system, you can check structure «COEP_ONLY» with the help of one of these
programs.

If you cannot solve the problem yourself and want to send an error
notification to SAP, include the following information:

1. The description of the current problem (short dump)

To save the description, choose «System->List->Save->Local File
(Unconverted)».

2. Corresponding system log

Display the system log by calling transaction SM21.
Restrict the time interval to 10 minutes before and five minutes
after the short dump. Then choose «System->List->Save->Local File
(Unconverted)».

3. If the problem occurs in a problem of your own or a modified SAP
program: The source code of the program
In the editor, choose «Utilities->More
Utilities->Upload/Download->Download».

4. Details about the conditions under which the error occurred or which
actions and input led to the error.

Информация о месте прерывания
The termination occurred during generation of the ABAP/4 program «ZBPC_EKP_R».

The termination occurred in line 69
of the source code of program «ZBPC_EKP_R_TOP» (when calling the editor 690).

Внутренние указания
The termination was triggered in function «ab_RxDdicTypeError»
of the SAP kernel, in line 1068 of the module
«//bas/720_REL/src/krn/runt/abucutil.c#4».
The internal operation just processed is » «.
Internal mode was started at 20130703180443.
There is an inconsistency in the DDIC structure «COEP_ONLY», the corresponding
dictionary runtime object (NAMETAB) is incorrect.

The number of components of the structure (NAMETAB component «fldcnt»)
is specified using 77. If you dismantle all the substructures and
calculate the actual total number of all the components recursively
then the result is a different value.

The error was caused because structure «COEP_ONLY» or one of its substructures
was changed and an error occurred in the subsequent activation. Please
check the runtime object of the structure «COEP_ONLY» in the dictionary to
analysis the exact error cause.

If the program RSDDCHECK is available on your system, you can also use
it to check structure «COEP_ONLY».

imagesКогда мы создаем какой-либо многократно используемый компонент, например функциональный модуль или метод в классе, мы сталкиваемся с необходимостью обработки непредвиденных ситуаций (какой-либо входной параметр, оказался не заполненным или доступ к файлу не был получен и т.п.), т.е. тех ситуаций, после которых программа не может выполняться далее стандартным образом, либо требуется дополнительная обработка.

В приведенной статье рассматриваются способы вызова и обработки данных ситуаций, называемых исключениями.

В ABAP есть два основных способа работы с исключениями, классический способ заключается в вызове особых ситуаций описанных в ФМ или методе на отдельной закладке:

1

Классический способ может использоваться и в классах:

2

Новый способ основывается на ООП, где в качестве исключений используются классы (обратите внимание, что установлена галочка – классы исключений):

3

Хочется отметить, что новый способ был введен с версии SAP Web AS 6.10 и при создании новых функциональных модулей или методов рекомендуется использовать именно его. В данной статье не рассматриваются системные исключения и их обработка до введения классов исключений.

В RFC модулях в настоящее время используется классический способ обработки исключений. Не допускается одновременно использовать классический и основанный на классах, способы обработки исключений (в интерфейсе методов, процедур, функций).

Классический способ обработки исключений

При вызове исключения, системное поле sy-subrc будет заполнено номером, под которым исключение было обозначено при вызове ФМ, метода или процедуры:

CALL FUNCTION ...

...

EXCEPTIONS

  Ошибка1 = 1

  Ошибка2 = 2.

Как правило, исключения вызываются с текстом сообщения, данный текст может быть описан статически – при вызове исключения оператором MESSAGE, либо динамически – путём получения текста из описания ФМ.

Так же исключение может быть вызвано без какого-либо текста (оператором RAISE ИмяИсключения), но данный способ лучше не использовать, т.к. вызов исключения должен как-то себя расшифровывать и говорить о том, что собственно произошло.

Напишем небольшой ФМ, рассчитывающий сумму двух чисел, оба параметра помечены как необязательные, если первый параметр не будет задан при вызове ФМ, система выдаст исключение – no_num_1.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

FUNCTION ZTEST_EXC.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH ‘Число 1 не указано, расчёт невозможен’ RAISING no_num_1.

  ENDIF.

  E_SUMM = i_num_1 + i_num_2.

ENDFUNCTION.

И программа для его вызова:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

DATA:

  gv_num_2 TYPE i VALUE 10,

  gv_summ  TYPE i.

CALL FUNCTION ‘ZTEST_EXC’

  EXPORTING

    i_num_2  = gv_num_2    » Число 2

  IMPORTING

    e_summ   = gv_summ     » Сумма

  EXCEPTIONS

    no_num_1 = 1

    others   = 2.

IF sysubrc <> 0.

MESSAGE ID symsgid TYPE symsgty NUMBER symsgno

            WITH symsgv1 symsgv2 symsgv3 symsgv4.

ENDIF.

WRITE gv_summ.

При запуске программы произойдет вызов исключения, т.к. был использован тип сообщения «Е», программа завершит свое выполнение после показа сообщения:

4

Замечу, что это вовсе не означает, что при вызове ФМ или метода и обработке исключения необходимо завершать работу программы, вы можете свободно продолжить её выполнение и далее, добавив например, сообщение об ошибке в лог программы, а не на вывод как в примере.

Ключевое слово OTHERS используется для того чтобы поймать исключения не описанные в ФМ или явно неуказанные, при вызове ФМ.

Пример вызова неописанного исключения:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

FUNCTION ztest_exc.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH ‘Число 1 не указано, расчёт невозможен’ RAISING no_num_2.

  ENDIF.

  E_SUMM = i_num_1 + i_num_2.

ENDFUNCTION.

В данном примере вызывается неописанное в интерфейсе ФМ исключение – no_num_2, которое будет благополучно поймано с помощью ключевого слова OTHERS (системное поле sy-subrc примет значение равное 2).

Кроме того, можно не обрабатывать большой список всех возможных исключений описанных в ФМ, тогда в случае если такое исключение будет вызвано поле sy-subrc примет значение, указанное в OTHERS.

В ФМ, могут быть добавлены новые исключения и в случае, когда при вызове ФМ они не обработаны и не указано слово OTHERS программа упадет в дамп с ошибкой времени выполнения — RAISE_EXCEPTION. Отсюда вывод, ключевое слово OTHERS подставляем всегда, при вызове ФМ (метода или процедуры), когда мы точно не уверены в неизменности компонента.

5

При вызове исключения в процедурах (perform…) из ФМ, система пытается найти и вызвать исключение в первом ФМ из стека вызовов, если исключение не найдено, вызывается так же, как и неопределенное исключение в ФМ.

Как уже было упомянуто выше, есть возможность получать текст непосредственно из описания особой ситуации:

6

ФМ будет выглядеть следующим образом:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

FUNCTION ztest_exc.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  DATA:

    lv_fun TYPE functfuncname,

    lv_exc TYPE functparameter,

    lv_txt TYPE swotlqshorttext.

  lv_fun = ‘ZTEST_EXC’.

  lv_exc = ‘NO_NUM_1’.

  CALL FUNCTION ‘SWO_TEXT_FUNCTION_EXCEPTION’

    EXPORTING

      language  = sylangu

      function  = lv_fun

      exception = lv_exc

    IMPORTING

      shorttext = lv_txt.

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH lv_txt RAISING no_num_1.

  ENDIF.

  e_summ = i_num_1 + i_num_2.

ENDFUNCTION.

Результат: 7

Иногда особые ситуации используются не как исключения, а как параметры показывающие обработку ФМ и его результат, возвращаемый в поле sy-subrc, хотя лучше бы пренебречь подобным стилем:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

FUNCTION ZMORE_THEN_10.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_VAL) TYPE  I

*»  EXCEPTIONS

*»      MORE_10

*»      LESS_10

*»      EQUAL_10

*»———————————————————————-

  IF i_val = 10.

    RAISE equal_10.

  ELSEIF i_val > 10.

    RAISE more_10.

  ELSE.

    RAISE less_10.

  ENDIF.

ENDFUNCTION.

Программа:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

DATA:

  gv_val TYPE i VALUE 10.

CALL FUNCTION ‘ZMORE_THEN_10’

  EXPORTING

    i_val    = gv_val

  EXCEPTIONS

    more_10  = 1

    less_10  = 2

    equal_10 = 3.

CASE sysubrc.

  WHEN 1.

    WRITE ‘More 10’.

  WHEN 2.

    WRITE ‘Less 10’.

  WHEN 3.

    WRITE ‘Equal

Результат:

8

Сообщения, вызываемые в ФМ или методах, оператором MESSAGE, без дополнения RAISING, либо сообщения вызываемые системой (например, при обработке экранов), могут быть обработаны программой с использованием дополнения: error_message = n_error, указываемого так же после ключевого слова EXCEPTIONS.

При обработке сообщений:

  • Сообщения с типом I, W, S не обрабатываются, но записываются в журнал обработки фонового выполнения, если происходит обработка в фоне.
  • Сообщения с типом E или A могут быть обработаны, при этом в поле sy-subrc будет записано значение n_error. При вызове сообщения с типом А, происходит вызов ROLLBACK WORK (см. описание оператора MESSAGE).
  • Сообщение с типом X не обрабатывается, программа завершается с дампом.

Пример ФМ:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

FUNCTION ztest_exc.

*»———————————————————————-

*»*»Локальный интерфейс:

*»  IMPORTING

*»     REFERENCE(I_NUM_1) TYPE  I OPTIONAL

*»     REFERENCE(I_NUM_2) TYPE  I OPTIONAL

*»  EXPORTING

*»     REFERENCE(E_SUMM) TYPE  I

*»  EXCEPTIONS

*»      NO_NUM_1

*»———————————————————————-

  IF i_num_1 IS NOT SUPPLIED.

    MESSAGE e398(00) WITH ‘Число 1 не указано, расчёт невозможен’.

  ENDIF.

  E_SUMM = i_num_1 + i_num_2.

ENDFUNCTION.

Программа:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

PROGRAM test_exceptions.

DATA:

  gv_val TYPE i VALUE 10,

  gv_summ TYPE i.

CALL FUNCTION ‘ZTEST_EXC’

  EXPORTING

    i_num_2  = gv_val    » Число 2

  IMPORTING

    e_summ   = gv_summ    » Сумма

  EXCEPTIONS

    error_message = 1

    others   = 2.

IF sysubrc = 1.

  WRITE ‘ФМ вызвал MESSAGE с типом E,A’.

ENDIF.

Результат:

9

Обработка исключения классическим способом может быть выполнена динамически, с помощью ключевого слова EXCEPTION-TABLE. Пример:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

DATA: line     TYPE c LENGTH 80,

      text_tab LIKE STANDARD TABLE OF line,

      filename TYPE string,

       filetype TYPE c LENGTH 10,

      fleng    TYPE i.

DATA: func TYPE string,

      ptab TYPE abap_func_parmbind_tab,

      ptab_line TYPE abap_func_parmbind,

      etab TYPE abap_func_excpbind_tab,

      etab_line TYPE abap_func_excpbind.

func = ‘GUI_DOWNLOAD’.

filename = ‘c:\temp\text.txt’.

filetype = ‘ASC’.

ptab_linename = ‘FILENAME’.

ptab_linekind = abap_func_exporting.

GET REFERENCE OF filename INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

ptab_linename = ‘FILETYPE’.

ptab_linekind = abap_func_exporting.

GET REFERENCE OF filetype INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

ptab_linename = ‘DATA_TAB’.

ptab_linekind = abap_func_tables.

GET REFERENCE OF text_tab INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

ptab_linename = ‘FILELENGTH’.

ptab_linekind = abap_func_importing.

GET REFERENCE OF fleng INTO ptab_linevalue.

INSERT ptab_line INTO TABLE ptab.

...

etab_linename = ‘OTHERS’.

etab_linevalue = 10.

INSERT etab_line INTO TABLE etab.

CALL FUNCTION func

  PARAMETERTABLE

  ptab

  EXCEPTIONTABLE

  etab.

CASE sysubrc.

  WHEN 1.

    ...

    ...

ENDCASE.

Обработка исключений, основанная на классах

Как понятно из названия, под исключениями в данном случае понимаются объекты специальных классов исключений. Вызов такого исключения может быть выполнен либо в программе с помощью оператора RAISE EXCEPTION, либо системой (например, при делении на ноль будет вызвано предопределённое исключение CX_SY_ZERODIVIDE, список таких исключений), либо через дополнение THROW в условных выражениях (с версии ABAP 7.4).

Во всех случаях инициируется создание объекта указанного класса (если указано дополнение INTO в CATCH), в атрибутах которого содержится информация о возникшей исключительной ситуации, доступ к ним, как правило, осуществляется через методы этого класса.

Классы особых ситуаций могут быть определены как локально, так и глобально через построитель классов – транзакция SE24, диалог создания:

10

В данном случае галочка «с классом сообщений» означает использование в качестве текста сообщения из класса сообщений транзакция SE91 (будет рассмотрено ниже). По умолчанию текст сообщения создается в текстах класса:

11

Категории исключений

Все классы особых ситуаций являются производными одного из классов: CX_NO_CHECK, CX_DYNAMIC_CHECK или CX_STATIC_CHECK, которые сами являются производными общего суперкласса CX_ROOT.

  • CX_STATIC_CHECK – как правило, исключения которые вызываются в процедуре (ФМ или методе), должны быть либо обработаны в ней, либо процедура должна иметь соответствующий интерфейс, чтобы вызывающий её код мог обработать эту ситуацию. Если исключение определено как потомок этого класса, оно должно быть явно указано в интерфейсе метода (ФМ или формы) в котором происходит его вызов. Данная категория используется тогда, когда в коде явно ожидается передача обработки особой ситуации на уровень выше того места где оно было вызвано. Если при статической проверке, система не увидит обработки в блоке TRY..CATCH..ENDTRY подобного исключения система выдаст предупреждение: 12
  • CX_DYNAMIC_CHECK – при проверке кода, компилятор не будет делать предупреждений об отсутствии обработки исключений их этой категории, в случае вызова исключения его обработка будет проверена динамически и если обработчик не будет найден программа упадет в дамп. Обычно данная категория используется тогда, когда исключение может быть обработано внутри самого метода, без передачи обработки выше по стеку. Примером такой категории может являться исключение вызываемое при делении на ноль, передавать его выше по стеку и указывать в интерфейсе метода вовсе не обязательно, т.к. мы можем его обработать внутри самого метода. Однако, если мы хотим передать обработку данного исключения, необходимо указать его в интерфейсе метода.
  • CX_NO_CHECK – аналогичны предыдущему типу, но данную категорию нельзя объявлять в интерфейсах, при этом классы исключений наследуемые от этого класса, неявно все же передаются в интерфейс и выше по стеку вызовов. Данную категорию следует использовать для исключительных ситуаций, которые могут произойти в любое время и не могут быть обработаны непосредственно в коде метода. Кроме того, можно использовать в случаях когда одна и та же исключительная ситуация может возникнуть во множествах методов, а объявлять её в интерфейсах каждого из методов не имеет смысла, т.к. это усложнит код. В итоге подобные исключения могут пройти всю цепочку вызовов методов (т.к. неявно передаются в интерфейс) и быть обработаны на уровне программы.

На исключения накладываются следующие ограничения:

  • Исключение не может быть объявлено в интерфейсе статического конструктора:

13

  • Исключение не может быть объявлено в интерфейсе обработчика событий. При этом если в коде обработчика произошел вызов исключения, и он не был обработан, система вызовет исключение — CX_SY_NO_HANDLER, которое может быть обработано в вызывающем его коде.
  • При вызове программ через SUMBIT или CALL TRANSACTION, исключение, возникающее в вызываемой программе, не может быть передано в вызывающую программу.

Небольшой пример с локальным классом исключения:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

PROGRAM test_exceptions.

CLASS lcx_no_num DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcl_test_exceptions DEFINITION.

  PUBLIC SECTION.

    METHODS:

      do_summ IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING value(re_summ) TYPE int1

              RAISING lcx_no_num.

ENDCLASS.

CLASS lcl_test_exceptions IMPLEMENTATION.

  METHOD do_summ.

    IF i_num_1 IS NOT SUPPLIED OR i_num_2 IS NOT SUPPLIED.

      » Данное исключение присутствует в интерфейсе, может быть обработано вне метода

      RAISE EXCEPTION TYPE lcx_no_num.

    ENDIF.

    TRY.

      re_summ = i_num_1 + i_num_2.

      » Ошибка с дин. проверкой, при её обработке обнулим результат

    CATCH CX_SY_CONVERSION_OVERFLOW.

      re_summ = 0.

    ENDTRY.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test_exceptions TYPE REF TO lcl_test_exceptions,

  gv_summ TYPE int1.

START-OF-SELECTION.

  CREATE OBJECT go_test_exceptions.

  TRY.

    go_test_exceptions>do_summ(

      EXPORTING

        i_num_2 = 1

      RECEIVING

        re_summ = gv_summ

    ).

  CATCH lcx_no_num.

    WRITE ‘Не заполнены все параметры’.

  ENDTRY.

  go_test_exceptions>do_summ(

    EXPORTING

      i_num_1 = 999

      i_num_2 = 1

    RECEIVING

      re_summ = gv_summ

  ).

  WRITE: / ‘Результат cуммы 999 и 1:’, gv_summ.

В стандартной системе SAP имена всех классов особых ситуаций начинаются с CX_ , пользовательские исключения рекомендуется называть, начиная с ZCX или lcx для локальных классов исключений.

Класс CX_ROOT предоставляет некоторые предопределенные методы, которые наследуются всеми классами особых ситуаций:

  • Метод GET_SOURCE_POSITION возвращает имя главной программы и (если связаны) имена включенных программ (инклудов) и номер строки исходного кода, в которой возникла особая ситуация.
  • Метод GET_TEXT возвращает текст особой ситуации в форме строки.
  • Метод GET_LONGTEXT возвращает подробный текст текста особой ситуации в форме строки.

Тексты исключений

Каждому классу можно присвоить несколько текстов. Присвоенные им идентификаторы создаются построителем классов как константы в атрибутах класса. Тексты сохраняются в репозитарии текстов (OTR). Константы идентификаторы, представленные в шестнадцатеричном формате, уникальны на уровне системы:

14

Доступ к хранилищу текстов можно получить через транзакцию SOTR_EDIT.

В текстах можно определить параметры, их необходимо обозначить в амперсандах. В качестве примера, можно рассмотреть текст из класса исключения — CX_SY_FILE_IO:

15

В параметры будут переданы (при вызове метода GET_TEXT) соответствующие им атрибуты класса:

16

Заполняются эти атрибуты в конструкторе при вызове исключения:

DATA: lr_ex  TYPE REF TO cx_sy_file_io,

      lv_msg TYPE string.

TRY.

   ...

   RAISE EXCPETION TYPE cx_sy_file_io

      EXPORTING

         textid = cx_sy_file_io=>read_error

         filename = ‘somefile.txt’.

CATCH cx_sy_file_io INTO lr_ex.

   lv_msg = lr_ex>get_text( ).

   MESSAGE lv_msg TYPE ‘I’.

ENDTRY.

Так же в конструкторе можно указать, какой текст должен использоваться при инициировании особой ситуации, передав одну из определенных констант в параметр импорта TEXTID. Не рекомендуется использовать подобную методику, т.к. это может запутать код, однако как было уже показано выше SAP сам это использует (read_error, write_error в CX_SY_FILE_IO). Инкапсуляция текстов в классах сообщений и их саморасшифровываемость является одним из преимуществ над классическими исключениями.

Конструктор, который генерируется автоматически в SE24, для нового созданного исключения (ZCX_NO_NUM1), выглядит так:

CALL METHOD SUPER>CONSTRUCTOR

EXPORTING

TEXTID = TEXTID

PREVIOUS = PREVIOUS

.

IF textid IS INITIAL.

   me>textid = ZCX_NO_NUM1 .

ENDIF.

Блок обработки исключений

Особая ситуация может быть обработана, только если оператор, который может инициировать ее, заключен в блок TRY-ENDTRY. Затем особая ситуация обрабатывается с помощью оператора CATCH в блоке TRY-ENDTRY.

17

Блок TRY содержит набор операторов, обрабатывающих особые ситуации. Если в блоке TRY появляется особая ситуация, система осуществляет поиск первого оператора CATCH в том же блоке TRY-ENDTRY, а затем последовательно снаружи во всех заключающих блоках TRY-ENDTRY, обрабатывающих особую ситуацию. Если оператор находится, система осуществляет переход к его обработчику. Если обработчик найти не удается, но блок TRY-ENDTRY находится в процедуре, система осуществляет попытку передачи особой ситуации вызывающей программе.

Блок CATCH содержит обработчик особых ситуаций, исполняемый при возникновении указанной особой ситуации в связанном блоке TRY. Для оператора CATCH можно указать любое количество классов особых ситуаций. Таким образом, определяется обработчик особых ситуаций для всех этих классов особых ситуаций и их подклассов.

Блоки TRY-ENDTRY могут иметь вложенность любой глубины. Поэтому блок TRY, блоки CATCH и блок CLEANUP в целом сами могут содержать полные блоки TRY-ENDTRY.

При возникновении особой ситуации система осуществляет поиск по перечисленным обработчикам особых ситуаций в указанном порядке. Затем она исполняет первый обработчик особых ситуаций, оператор CATCH которого содержит подходящий класс особой ситуации или один из ее суперклассов.

Если ошибка не будет обработана и не будет передана вызывающей программе, система выдаст дамп с ошибкой времени выполнения — UNCAUGHT_EXCEPTION, в том случае когда не обрабатывается исключительная ситуация, связанная с ошибкой времени выполнения, система выдает дамп с ошибкой времени выполнения (например, CX_SY_CONVERSION_CODEPAGE — CONVT_CODEPAGE):

18

Просмотр ошибки в транзакции ST22:Безымянный

Распространение особых ситуаций

Если возникает особая ситуация (наследуемая от CX_DYNAMIC_CHECK, CX_STATIC_CHECK), она автоматически распространяется на все уровни стека вызовов, до тех пор, пока она не будет обработана или пока не встретится такой интерфейс, в котором она (либо её предки) будет отсутствовать.

Следующий пример демонстрирует распространение особой ситуации на несколько методов:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

CLASS lcx_calc_error DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcx_summ_error DEFINITION INHERITING FROM lcx_calc_error.

ENDCLASS.

CLASS lcl_test_exc DEFINITION.

  PUBLIC SECTION.

  METHODS:

    do_calc

      RAISING

        lcx_calc_error,

    do_summ

      RAISING

        lcx_summ_error.

ENDCLASS.

CLASS lcl_test_exc IMPLEMENTATION.

  METHOD do_calc.

    do_summ( ).

  ENDMETHOD.

  METHOD do_summ.

    RAISE EXCEPTION TYPE lcx_summ_error.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test TYPE REF TO lcl_test_exc.

START-OF-SELECTION.

  CREATE OBJECT go_test.

  TRY.

    go_test>do_calc( ).

  CATCH lcx_calc_error.

    WRITE ‘Catched’.

  ENDTRY.

Обратите внимание на метод do_calc, в нем описана особая ситуация от которой наследуется lcx_summ_error, соответственно прерывание продолжится на следующий уровень и будет обработано в блоке TRY..CATCH..ENDTRY. При правильно выстроенной архитектуре наследования исключительных ситуаций, прозрачность кода заметно повышается.

В случае, когда используется исключение, наследуемое от CX_NO_CHECK, описание его в интерфейсе метода может быть опущено, т.к. оно инициируется неявным способом системой:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

CLASS lcx_calc_error DEFINITION INHERITING FROM cx_no_check.

ENDCLASS.

CLASS lcx_summ_error DEFINITION INHERITING FROM lcx_calc_error.

ENDCLASS.

CLASS lcl_test_exc DEFINITION.

  PUBLIC SECTION.

  METHODS:

    do_calc,

    do_summ.

ENDCLASS.

CLASS lcl_test_exc IMPLEMENTATION.

  METHOD do_calc.

    do_summ( ).

  ENDMETHOD.

  METHOD do_summ.

    RAISE EXCEPTION TYPE lcx_summ_error.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test TYPE REF TO lcl_test_exc.

START-OF-SELECTION.

  CREATE OBJECT go_test.

  TRY.

    go_test>do_calc( ).

  CATCH lcx_calc_error.

    WRITE ‘Catched’.

  ENDTRY.

Очистка после вызовов исключений

Блок CLEANUP исполняется, когда выполнен выход из блока TRY-ENDTRY, так как система не смогла найти обработчик для исключения в определенном блоке TRY-ENDTRY, но особая ситуация обрабатывается в окружающем блоке TRY-ENDTRY или передается вызывающей программе.

Данный блок обычно применяется для освобождения занятых ресурсов: очистке ссылочных переменных, закрытие локаторов или наборов данных (datasets) и т.п. Допустим, Вы записываете некоторые данные в файл на сервере приложений. Внутри блока TRY Вы открываете набор данных (dataset) и начинаете запись в него. Однако в некоторый момент, случается особая ситуация, которую вы не обработали и блок TRY прерывает свою работу, при этом, не выполнив закрытие набора данных. Для того чтобы избежать подобной ситуации воспользуемся ключевым словом CLEANUP:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

TRY.

*  Открываем файл на запись:

   OPEN DATASET lv_file FOR OUTPUT IN TEXT MODE

                        ENCODING DEFAULT.

*  Переносим данные в файл:

   LOOP AT lt_extract INTO ls_record.

      PERFORM sub_format_record CHANGING ls_record.

      TRANSFER ls_record TO lv_file.

   ENDLOOP.

*  Закрываем файл:

   CLOSE DATASET lv_file.

CATCH cx_sy_file_access_error INTO lr_file_ex.

*  Ошибки ввода, вывода (датасет в таком случае не открыт)…

CATCH lcx_format_error INTO lr_format_ex.

*  Обрабатываем свою внутренюю ошибку при форматировании…

*  при этом необходимо закрыть набор данных

   CLOSE DATASET lv_file.

CLEANUP.

*  В случае если возникнет не обработанное исключение закроем набор данных:

   CLOSE DATASET lv_file.

ENDTRY.

В случае возобновляемых оператором RESUME исключений, блок CLEANUP не выполняется. Блок CLEANUP, как и блок CATCH позволяет получить ссылочную переменную на вызванное исключение, с помощью дополнения [INTO oref].

Передача исключений по цепочке

Необходимо понимать, что особая ситуация может передаваться через любое количество иерархий вызова перед финальной обработкой. Одна особая ситуация может инициировать вторую и т. д. Каждая инстанция должна оставаться действительной, независимо то того, был ли связанный блок CATCH уже обработан или нет. Поэтому необходимо убедиться, что предыдущая инстанция особой ситуации доступна с помощью, по крайней мере, одной ссылки. Атрибут общей инстанции PREVIOUS, наследуемый всеми классами особых состояний из CX_ROOT, обеспечивает удобный для этого способ.

Пример:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

CLASS lcx_very_big DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcx_calc_error DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcl_test_exceptions DEFINITION.

  PUBLIC SECTION.

    METHODS:

      do_calc IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING VALUE(re_result) TYPE i

              RAISING lcx_calc_error.

  PRIVATE SECTION.

    METHODS:

      do_summ IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING value(re_summ) TYPE i

              RAISING lcx_very_big.

ENDCLASS.

CLASS lcl_test_exceptions IMPLEMENTATION.

  METHOD do_summ.

    re_summ = i_num_1 + i_num_2.

    IF re_summ > 100.

      RAISE EXCEPTION TYPE lcx_very_big.

    ENDIF.

  ENDMETHOD.

  METHOD do_calc.

    DATA:

      lo_very_big TYPE REF TO lcx_very_big.

    TRY.

      me>do_summ(

        EXPORTING

          i_num_1 = i_num_1

          i_num_2 = i_num_2

        RECEIVING

          re_summ = re_result

      ).

    CATCH lcx_very_big INTO lo_very_big.

      RAISE EXCEPTION TYPE lcx_calc_error EXPORTING previous = lo_very_big.

    ENDTRY.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test_exceptions TYPE REF TO lcl_test_exceptions,

  gv_result TYPE i,

  go_calc_error TYPE REF TO lcx_calc_error,

  go_big_error  TYPE REF TO lcx_very_big.

START-OF-SELECTION.

  CREATE OBJECT go_test_exceptions.

  TRY.

    go_test_exceptions>do_calc(

      EXPORTING

        i_num_1   = 1000

        i_num_2   = 500

      RECEIVING

        re_result = gv_result

    ).

  CATCH lcx_calc_error INTO go_calc_error.

    go_big_error ?= go_calc_error>previous.

  ENDTRY.

Таким образом, пройдя по цепочке, мы всегда можем определить, в каком конкретном месте было инициировано исключение и что из-за этого произошло. Иногда при построении какой-либо ООП модели, удобно собрать всю цепочку из ошибок в каком-нибудь одном виде и выдать в качестве универсального исключения, в качестве примера рекомендую посмотреть этот пример.

Возобновляемые исключения и повтор блока TRY

При срабатывании исключения, выполнение программы в текущем контексте завершается. Иногда необходимо не завершать выполнение текущего контекста, для этого были созданы так называемые возобновляемые исключения. Для того чтобы вызвать такое исключение, необходимо в операторе RAISE (или в THROW) указать что вызывается именно возобновляемое исключение, при этом для того чтобы воспользоваться оператором RESUME (который возвращает код обратно в то место где было вызвано исключение), необходимо у оператора CATCH указать дополнение BEFORE UNWIND (обозначает обработку возобновляемого исключения), иначе система вызовет исключение CX_SY_ILLEGAL_HANDLER. При возврате в контекст, из которого было вызвано исключение блок CLEANUP не вызывается. Если в указанном в CATCH блоке не будет вызван оператор RESUME, контекст будет удален при выходе из блока CATCH.

Пример обработки возобновляемого исключения:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

CLASS lcx_no_num DEFINITION INHERITING FROM cx_static_check.

ENDCLASS.

CLASS lcx_less_zero DEFINITION INHERITING FROM cx_no_check.

ENDCLASS.

CLASS lcl_test_exceptions DEFINITION.

  PUBLIC SECTION.

    METHODS:

      do_summ IMPORTING

                i_num_1 TYPE i OPTIONAL

                i_num_2 TYPE i OPTIONAL

              RETURNING value(re_summ) TYPE int1

              RAISING RESUMABLE(lcx_no_num).

ENDCLASS.

CLASS lcl_test_exceptions IMPLEMENTATION.

  METHOD do_summ.

    IF i_num_1 IS NOT SUPPLIED OR i_num_2 IS NOT SUPPLIED.

      » Данное исключение присутствует в интерфейсе, может быть обработано вне метода

      RAISE RESUMABLE EXCEPTION TYPE lcx_no_num.

    ENDIF.

    TRY.

      re_summ = i_num_1 + i_num_2.

      » Динамическая ошибка, при её обработке обнулим результат

    CATCH CX_SY_CONVERSION_OVERFLOW.

      re_summ = 0.

    ENDTRY.

  ENDMETHOD.

ENDCLASS.

DATA:

  go_test_exceptions TYPE REF TO lcl_test_exceptions,

  gv_summ TYPE int1.

START-OF-SELECTION.

  CREATE OBJECT go_test_exceptions.

  TRY.

    go_test_exceptions>do_summ(

      EXPORTING

        i_num_2 = 1

      RECEIVING

        re_summ = gv_summ

    ).

  CATCH BEFORE UNWIND lcx_no_num.

    RESUME.

  ENDTRY.

  WRITE: / ‘Cумма без указания 1-го числа’, gv_summ.

  go_test_exceptions>do_summ(

    EXPORTING

      i_num_1 = 999

      i_num_2 = 1

    RECEIVING

      re_summ = gv_summ

  ).

  WRITE: / ‘Результат cуммы 999 и 1:’, gv_summ.

При обработке исключений так же есть возможность повтора блока TRY..CATCH, делается это с использованием оператора RETRY. Пример:

PARAMETERS: number1 TYPE i,

            number2 TYPE i.

DATA result  TYPE p DECIMALS 2.

TRY.

    result = number1 / number2.

  CATCH cx_sy_zerodivide.

    number1 = 0.

    RETRY.

ENDTRY.

В данном случае если номер 2 будет равен нулю, система вызовет исключение, с помощью RETRY мы заново запустим блок TRY..CACTH, при этом уже исключение не возникнет, т.к. при делении нуля на ноль результатом будет ноль.

Отображение сообщений из классов сообщений в тексты исключений

Начиная с версии 6.40, появилась возможность связывать тексты исключительных сообщений с классами сообщений (транзакция SE91). Как уже упоминалось выше для этого необходимо в конструкторе класса, указать галочку класс сообщений. При этом вместо интерфейса IF_MESSAGE будет внедрен интерфейс IF_T100_MESSAGE (таблица T100 хранит в себе эти сообщения):

19

При редактировании текста, необходимо будет привязать его к классу и номеру сообщения, при этом заполнить параметры, если это необходимо:

20

Начиная с NW 2004, оператор MESSAGE позволяет напрямую обработку исключений, внедряющих интерфейс IF_T100_MESSAGE:

TRY.

   ...

CATCH cx_some_exception INTO lr_ex.

   MESSAGE lr_ex TYPE ‘E’.

ENDTRY.

Локальный класс исключения в приватном методе глобального класса

Бывают ситуации, когда для какого-либо приватного метода необходимо реализовать исключение, которое может быть вызвано исключительно данным методом (классом).  Реализовать подобное можно, если создать локальный класс исключений:

  • Перейти в локальные определения/внедрения:

21

  • Создать класс исключения:

22

  •  Указать в методе имя локального класса исключения (обязательно в режиме редактирования исходного кода):

23

Результат:

24

Если попробовать сделать тоже самое в режиме редактирования на основе формуляров, выскочит предупреждение о том, что такого класса не существует:

25

Более подробно об исключениях можно почитать в официальной документации:

http://help.sap.com/abapdocu_740/en/abenabap_exceptions.htm

SAP R/3 форум ABAP консультантов
Russian ABAP Developer’s Club

View previous topic :: View next topic  
Author Message
SKD1980
Участник
Участник

Joined: 13 Jul 2010
Posts: 16

PostPosted: Thu Jun 30, 2011 7:51 am    Post subject: Ошибка при работе в фоновом режиме. Reply with quote

Добрый день! При запуске программы в фоновом режиме выскакивает динамическая ошибка RAISE_EXCEPTION. Exception condition «NO_BATCH» raised. Хотя если запускать программу с такими же параметрами вручную, то все работает отлично. Может кто-нибудь сталкивался с данной проблемой? Посоветуйте, пожалуйста, где искать, что править?

Last edited by SKD1980 on Thu Jun 30, 2011 10:10 am; edited 3 times in total

Back to top

View user's profile Send private message

Удав
Гуру
Гуру

Age: 47
Joined: 25 Jan 2008
Posts: 580
Location: Москва

PostPosted: Thu Jun 30, 2011 9:20 am    Post subject: Reply with quote

«Программа не работает!»(с) Very Happy

Уважаемый SKD1980!

Если Вы хотите, чтобы Вам помогли — пожалуйста, кроме слов приложите файл с дампом или хотя бы укажите название программы(транзакции).


_________________
С уважением,

Удав.

Back to top

View user's profile Send private message

RA
Участник
Участник

Joined: 03 Dec 2007
Posts: 13

PostPosted: Thu Jun 30, 2011 10:20 am    Post subject: Reply with quote

ФМ WS_QUERY не работает в фоновом режиме.

следовательно:

1. не запускать в фоне.

2. исправлять код.

Back to top

View user's profile Send private message

Dmitriy
Аналитик
Аналитик

Age: 46
Joined: 14 Nov 2008
Posts: 300
Location: Russia

PostPosted: Thu Jun 30, 2011 12:07 pm    Post subject: Reply with quote

Ну вот, и Удава довели… Mad

SKD1980 просто ещё не настолько опытен и невнимательно прочел информацию в блоке «Анализ ошибки» дампа.

Как уже сказал коллега RA и написано в вышеназванном блоке:

Quote:
Front-End Function Cannot Be Executed in Background.



И вылетает на проверке:

Code:
  CALL FUNCTION ‘GUI_IS_AVAILABLE’

    IMPORTING

      RETURN = GUI_EXIST.

  IF GUI_EXIST IS INITIAL.

    RAISE NO_BATCH.

  ENDIF.

SKD1980, повнимательнее пожалуйста, Удав у нас один! Smile


_________________
ABAP/4 You

Back to top

View user's profile Send private message

Удав
Гуру
Гуру

Age: 47
Joined: 25 Jan 2008
Posts: 580
Location: Москва

PostPosted: Thu Jun 30, 2011 12:32 pm    Post subject: Reply with quote

Дмитрий, почему сразу «довели»? Laughing

Я как раз объяснил политику партии человеку Wink

_________________
С уважением,

Удав.
Back to top

View user's profile Send private message

Dmitriy
Аналитик
Аналитик

Age: 46
Joined: 14 Nov 2008
Posts: 300
Location: Russia

PostPosted: Thu Jun 30, 2011 1:07 pm    Post subject: Reply with quote

Удав wrote:
Дмитрий, почему сразу «довели»? Laughing

Я как раз объяснил политику партии человеку Wink



(с)Так бы сразу и сказал! Laughing

P.S. Прежде чем паниковать и постить о своих проблемах на форуме, пусть даже прикладывая файлы/скриншоты/логи и всё остальное (как это совершенно обосновано требует не только Удав!) необходимо взять небольшой таймаут, посидеть и подумать. Почитать, что система пишет, сделать пару щелчков в Google с ключевыми словами проблемы. Проверено — помогает! Cool


_________________
ABAP/4 You

Back to top

View user's profile Send private message

SKD1980
Участник
Участник

Joined: 13 Jul 2010
Posts: 16

PostPosted: Thu Jun 30, 2011 3:43 pm    Post subject: Reply with quote

Простите! Постараюсь брать паузу и не нагружать уважаемых здесь людей глупыми вопросами. Спасибо за разъяснения Smile
Back to top

View user's profile Send private message

Dmitriy
Аналитик
Аналитик

Age: 46
Joined: 14 Nov 2008
Posts: 300
Location: Russia

PostPosted: Thu Jun 30, 2011 5:11 pm    Post subject: Reply with quote

SKD1980 wrote:
Простите! Постараюсь брать паузу и не нагружать уважаемых здесь людей глупыми вопросами. Спасибо за разъяснения Smile



Да ничего. Поворчит немного — и успокоится… Wink

_________________
ABAP/4 You

Back to top

View user's profile Send private message

Display posts from previous:   
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


All product names are trademarks of their respective companies. SAPNET.RU websites are in no way affiliated with SAP AG.
SAP, SAP R/3, R/3 software, mySAP, ABAP, BAPI, xApps, SAP NetWeaver and any other are registered trademarks of SAP AG.
Every effort is made to ensure content integrity. Use information on this site at your own risk.

Обработка исключений

Обработка исключений — это то, что происходит, когда система выдает ошибку.

Во время выполнения программы программа может столкнуться с ошибками. Иногда ошибки вносятся программистами случайно, но большинство ошибок связано с неправильным обращением с приложением. Ошибочные ситуации можно предвидеть во время разработки приложения, но просто невозможно избежать всех типов ошибок.

Обзор исключений

Отображение сообщения в процедуре на самом деле не имеет смысла, поскольку сообщения предназначены для отображения пользователю. В случае с процедурами рекомендуемым способом обработки ситуации с ошибкой является возбуждение исключения и предоставление вызывающей программе возможности решить, что делать с исключением.

Например, предположим, что мы разработали функциональный модуль, который принимает номер материала в качестве параметра импорта и экспортирует различные сведения о материале. Если номер материала, импортированный в функциональный модуль, недействителен, то вместо отображения сообщения о том, что номер материала недействителен, мы можем вызвать исключение в функциональном модуле, которое вызывающая программа может обработать в соответствии со своими функциональными требованиями. То есть вызывающая программа может либо показать сообщение об ошибке, либо выполнить другие действия. Кроме того, поскольку процедуры предназначены для повторного использования, вызывая исключения в процедуре, разные программы могут обрабатывать их по-разному в соответствии со своими конкретными требованиями.

Процедурная обработка исключений

До появления исключений на основе классов только функциональные модули и методы могли вызывать самоопределяемые обрабатываемые исключения, а логика обработки исключений смешивалась с реальной логикой программы.

Поддержка исключений с помощью функциональных модулей

Исключения статически поддерживаются в функциональном модуле с пояснительным текстом, объясняющим ситуацию исключения. Когда возникает это исключение, системное поле SY-SUBRC устанавливается с номером исключения, который вызывающая программа может проверить, чтобы реализовать пользовательскую логику обработки ошибок.

Функциональный модуль Z_TEST_EXCEPTION_EXAMPLE поддерживает два исключения: NOT_FOUND и NO_AIRLINE_DATA. При вызове этого функционального модуля в функциональном модуле возникает соответствующее исключение, если возникает ситуация ошибки. Вызывающая программа проверяет значение SY-SUBRC, чтобы идентифицировать исключение и поддерживать соответствующую логику обработки ошибок в программе.

DATA lt_spfli TYPE spfli_tab.
CALL FUNCTION 'Z_TEST_EXCEPTION_EXAMPLE'
  EXPORTING
    iv_id        = 'LH'
  IMPORTING
    et_itab      = lt_spfli
  EXCEPTIONS
    NOT_FOUND       = 1
    NO_AIRLINE_DATA = 2
    OTHERS          = 3.
CASE sy-subrc.
  WHEN 1.
* Обработка исключения
* NOT_FOUND
  WHEN 2.
* Обработка исключения
* NO_AIRLINE_DATA  
  WHEN OTHERS.
* Обработка других исключений
ENDCASE.

Эти самоопределяемые исключения поддерживаются вручную в функциональных модулях и методах и вызываются с помощью оператора RAISE внутри функционального модуля или метода.

Когда возникает первое исключение, функциональный модуль закрывается, и управление передается обратно вызывающей программе без выполнения дополнительного кода в функциональном модуле. Если вызывающая программа не перехватывает исключение, генерируется ошибка времени выполнения (короткий дамп). По этой причине всегда рекомендуется использовать ключевое слово EXCEPTIONS в вызове функционального модуля (CALL FUNCTION) для перехвата исключений, даже если вы не планируете реализовывать какую-либо пользовательскую логику для исключения.

Поддержка исключений с помощью методов

Подобно функциональным модулям, исключения можно поддерживать в методах с помощью Class Builder, удерживая курсор на методе и выбирая кнопку «Исключение», как показано ниже.

В столбце «Исключение» на вкладке «Метод» дайте имя исключению и сохраните описание, объясняющее исключение, чтобы разработчики, вызывающие метод, могли понять, почему возникает это исключение.

Как показано, в методе можно вызвать исключение с помощью оператора RAISE

.

Обратите внимание, что исключения специфичны для процедуры в том смысле, что если исключение поддерживается для функционального модуля, оно может быть вызвано только внутри этого функционального модуля и не может быть вызвано другими функциональными модулями функциональной группы. Точно так же исключение, поддерживаемое для метода, может быть вызвано только внутри этого метода и не может быть вызвано другими методами класса.

Исключений для локальных классов

Для локальных классов исключения можно определить с помощью оператора EXCEPTIONS в части определения класса, как показано ниже. Исключения, определенные в части определения класса, могут быть вызваны методами, реализованными в части реализации того же класса.

CLASS lcl_test_class DEFINITION
  PUBLIC.

  PUBLIC SECTION.
    CLASS-METHODS read_spfli_into_table
      IMPORTING
        VALUE(iv_id)   TYPE spfli-carrid DEFAULT 'LH '
      EXPORTING
        VALUE(et_itab) TYPE spfli_tab
      EXCEPTIONS
        not_found         "Запись не найдена
        no_airline_data . "Нет данных авиакомпании

ENDCLASS.

Мы определили исключение NOT_FOUND в части определения класса LCL_TEST_CLASS. Исключения определяются с помощью ключевого слова EXCEPTIONS. Рекомендуется поддерживать комментарий с кратким описанием исключения.

Обработка исключений на основе классов

Исключения на основе классов (объектно-ориентированные) помогают отделить логику обработки исключений от основной логики программирования, обрабатывая исключения в отдельном блоке. В предыдущем разделе, посвященном процедурным методам обработки исключений, вы видели, что помимо проверки системного поля SY-SUBRC для идентификации исключения, информации об исключении не так много.

Кроме того, поскольку самоопределяемые исключения поддерживаются только в функциональных модулях и методах, в обычных программах нет правильного способа обработки ошибок. Например, если в подпрограмме возникает ситуация ошибки, в которой самоопределяемые исключения не поддерживаются, как мы можем с этим справиться?

Один из способов — передать структуру ошибки или какую-либо переменную в интерфейс параметров и проверить ее после выполнения подпрограммы, как показано ниже.

DATA: lv_carrid  TYPE scarr-carrid,
      lt_spfli   TYPE spfli_tab,
      lv_retcode.

PERFORM read_spfli_into_table USING    lv_carrid
                              CHANGING lt_spfli
                                       lv_retcode.
IF lv_retcode IS INITIAL.
*Логика программы
ELSE.
*Логика обработки ошибок
ENDIF.

FORM read_spfli_into_table USING    iv_id
                           CHANGING ct_itab TYPE spfli_tab
                                    cv_retcode.

    SELECT SINGLE carrid INTO @DATA(lv_carrid) FROM scarr  WHERE carrid = @iv_id.
    IF sy-subrc NE 0.
      cv_retcode = 1.
    ENDIF.
    SELECT * FROM spfli WHERE carrid = @iv_id INTO TABLE @ct_itab.
    IF sy-subrc NE 0.
      cv_retcode = 2.
    ENDIF.
ENDFORM.

Как вы можете видеть, код использует параметр LV_RETCODE, чтобы зафиксировать ситуацию с ошибкой и соответствующим образом построить логику программы для обработки исключения. Однако это не самый элегантный способ обработки исключений, и интерфейс может вскоре стать загроможденным, если необходимо обработать множество исключительных ситуаций. Это также создает проблемы при пересылке исключения, если исключение необходимо обработать в другом блоке обработки. Например, большинство BAPI реализуют структуру ошибок в интерфейсе для захвата ошибки. В этой структуре ошибки фиксируется большая часть информации об ошибке, например тип ошибки, идентификатор ошибки, сообщение и т. д.

Теперь мы хотим передать эти сведения об ошибке другому функциональному модулю, вызываемому в BAPI, в котором может быть обработано исключение. Для этого нам нужно убедиться, что BAPI и функциональный модуль, вызываемый в BAPI, имеют схожие структуры ошибок; в противном случае нам нужно вручную преобразовать данные и присвоить их новой структуре ошибок функционального модуля.

Вопреки тому, что предполагают многие разработчики, исключения на основе классов не ограничиваются объектами ABAP. Их можно использовать в любом блоке обработки. Исключения на основе классов обрабатываются с помощью специального блока, называемого блоком TRY. Используя операторы CATCH и CLEANUP, мы можем обрабатывать исключения в блоке TRY. Оператор CATCH может перехватывать несколько исключений внутри блока, а оператор CLEANUP позволяет выполнять задачи очистки при выходе из исключения. Например, если вы открываете файл для вывода и сталкиваетесь с исключением при передаче одной из записей, то блок очистки позволяет закрыть файл.

Raising Exceptions

Исключения возникают в нескольких ситуациях — либо программно с помощью оператора RAISE EXCEPTION, либо автоматически средой выполнения ABAP. Например, если мы выполним код ниже, это приведет к ошибке времени выполнения.

DATA : lv_unit_value  TYPE i,
       lv_total_value TYPE i VALUE 20,
       lv_quantity    TYPE i.
lv_unit_value = lv_total_value / lv_quantity.

Показан класс исключений, который выдается системой при делении операнда на ноль. Мы можем избежать короткого дампа, перехватив исключение в нашей программе и выйдя из ситуации исключения.

Ниже показан синтаксис реализации блока TRY для обработки исключений.

DATA lx_ex TYPE REF TO cx_sy_zerodivide.
DATA : lv_unit_value  TYPE i,
       lv_total_value TYPE i VALUE 20,
       lv_quantity    TYPE i.
TRY. "Начало блока TRY
    lv_unit_value = lv_total_value / lv_quantity.
*Другая логика программирования
  CATCH cx_sy_zerodivide INTO lx_ex.
    WRITE :/'Короткий текст ошибки:' , lx_ex->get_text( ).
    WRITE :/'Длинный текст ошибки:' , lx_ex->get_longtext( ).
  CLEANUP.
* Любая логика очистки
ENDTRY. "Конец TRY блока

Код приводит к выводу, показанному ниже. Здесь система не генерировала короткий дамп, потому что мы поймали исключение в программе и обработали исключительную ситуацию программно. Хорошая практика программирования состоит в том, чтобы избегать таких исключительных ситуаций, проверяя знаменатель перед его использованием при делении (например, IF lv_quantity IS NOT INITIAL ).

Перехватываемые и неперехватываемые исключения

Существует два типа исключений, генерируемых системой: перехватываемые и неперехватываемые. Для перехватываемых исключений мы можем использовать структуру управления TRY для перехвата исключения в программе, неперехватываемые исключения приводят к ошибке времени выполнения.

Мы можем найти информацию о различных возможных исключениях, вызванных системой, проверив документацию по любому конкретному ключевому слову, и реализовать подходящую обработку исключений в нашей программе. Все классы системных исключений начинаются с CX_SY_.

Возвращаясь к коду, мы определили перехватываемое исключение CX_SY_ZERODIVIDE, которое вызывается системой, когда она сталкивается со значением, делящимся на ноль. Единственная ситуация, в которой системное исключение не возникает при таких обстоятельствах, — это когда числитель также равен нулю. Здесь CX_SY_ZERODIVIDE — это глобальный класс с определенными компонентами.

Как видно, класс CX_SY_ZERODIVIDE реализует интерфейс IF_MESSAGE с двумя методами: GET_TEXT и GET_LONGTEXT. Псевдонимы для этих методов сохраняются на вкладке Псевдонимы.

Мы определили ссылочный объект LX_ER, ссылающийся на статический тип CX_SY_ZERODIVIDE. В управляющей структуре TRY оператор CATCH cx_sy_zerodivide INTO lx_ex создает экземпляр объекта LX_EX. Мы получили доступ к короткому и полному тексту ошибки, вызвав методы GET_TEXT и GET_LONGTEXT соответственно.

При желании мы также сохранили блок CLEANUP, в котором может храниться подходящий код выхода для корректного выхода из процедуры. Например, блок CLEANUP можно использовать для закрытия любых открытых файлов или отката любых обновлений базы данных.

Если вы внимательно посмотрите на класс CX_SY_ZERODIVIDE, то увидите, что он наследуется от суперкласса CX_SY_ARITHMETIC_ERROR. Класс CX_SY_ARITHMETIC_ERROR, в свою очередь, наследуется от суперкласса CX_DYNAMIC_CHECK, который наследуется от CX_ROOT

Базовым классом для всех классов исключений является CX_ROOT, который реализует интерфейсы IF_MESSAGE и IF_SERIALIZABLE_OBJECT. Интерфейс IF_MESSAGE содержит методы GET_TEXT и GET_LONGTEXT, позволяющие извлечь сообщение об ошибке. Интерфейс IF_SERIALIZABLE_OBJECT используется для сериализации объектов — процесса, в котором объект преобразуется в формат сериализации (например, XML, CSV), который может быть передан для создания клона объекта в той же или другой системе. Интерфейс IF_SERIALIZABLE_OBJECT должен быть реализован, если объект исключения необходимо сериализовать. Класс CX_ROOT также реализует другой метод, GET_SOURCE_position, который возвращает позицию в исходном коде, вызвавшую ошибку.

При перехвате исключений на основе классов информация об исключении захватывается объектом, который является экземпляром класса, наследуемого от одного из трех глобальных абстрактных классов: CX_STATIC_CHECK, CX_DYNAMIC_CHECK или CX_NO_CHECK. Эти три глобальных абстрактных класса, в свою очередь, являются подклассами CX_ROOT. Например, мы можем определить ссылочный объект LX_ER как экземпляр класса CX_ROOT вместо класса CX_SY_ZERODIVIDE и по-прежнему иметь возможность перехватывать исключение, как показано в листинге 9.6. Однако это сделает логику ошибки общей и упустит какие-либо конкретные детали обработки исключений, поддерживаемые в конкретном классе исключений.

Как уже отмечалось, при определении пользовательского класса исключений он должен наследоваться от одного из трех классов:

CX_STATIC_CHECK 

Если класс исключения, являющийся подклассом CX_STATIC_CHECK, вызывается в функциональном модуле или методе, он должен быть либо определен в сигнатуре (интерфейс параметра), либо перехвачен в процедуре внутри блока TRY. В противном случае средство проверки синтаксиса выводит предупреждающее сообщение.

CX_DYNAMIC_CHECK

Подобно CX_STATIC_CHECK, если класс исключения, который является подклассом CX_DYNAMIC_CHECK, возникает в функциональном модуле или методе, он должен быть либо определен в сигнатуре (интерфейс параметра), либо перехвачен в процедуре внутри блока TRY. В противном случае компилятор не выдаст статическое предупреждающее сообщение, а выдаст ошибку времени выполнения.

CX_NO_CHECK

Класс исключения, который является подклассом CX_NO_CHECK, не может быть определен в сигнатуре функционального модуля или метода. Он неявно объявлен по умолчанию и всегда передается вызывающей стороне.

Поскольку CX_STATIC_CHECK проверяется компилятором во время разработки, рекомендуется использовать этот класс для определения классов исключений. Большинство системных исключений являются производными от CX_DYNAMIC_CHECK.

Глобальное определение классов исключений

Чаще всего мы определяем классы исключений глобально, чтобы их можно было использовать в нескольких программах. Действия по созданию класса исключения в Class Builder аналогичны действиям по созданию любого обычного класса, за исключением того, что класс исключения должен наследовать CX_STATIC_CHECK, CX_DYNAMIC_CHECK или CX_NO_CHECK или любой класс, наследующий эти классы.

Кроме того, классы исключений должны следовать соглашению об именах CX_ для пространства имен SAP и ZCX_ для пространства имен клиента. Флажок «Класс исключения» также установлен для класса исключения.

Флажок «С классом сообщений» позволит вам использовать класс сообщений для хранения сообщений.

Вы заметите, что Class Builder создаст класс исключений, которая похожа на обычный класса, за исключением незначительных дополнительных опций. Например, вы увидите вкладку «Тексты», которая недоступна при создании обычных классов.

SAP рекомендует не определять новые методы и не переопределять унаследованные методы.

Исключение можно вызвать внутри функционального модуля, используя синтаксис RAISE EXCEPTION TYPE класс_исключений.

Локальное определение классов исключений

Локальные классы исключений могут быть определены для локальной работы с исключениями внутри программы. Синтаксис определения локального класса исключений подобен обычному классу, за исключением того, что он должен наследовать CX_STATIC_CHECK, CX_DYNAMIC_CHECK или CX_NO_CHECK. Соглашение об именах LCX_ используется для локальных классов исключений.

Помимо их видимости, работа с локальными классами исключений аналогична работе с глобальными классами исключений.

Сообщения в классах исключений

Классы исключений позволяют нам изящно выйти из ситуации исключения. Однако иногда исключение вызвано ошибкой, для исправления которой может потребоваться вмешательство человека. В таких ситуациях мы можем перехватить сообщение, когда возникнет исключение, чтобы можно было идентифицировать ошибку. Для этого мы можем передать текстовое сообщение с исключением. Тексты также могут иметь значения динамических полей для дополнения сообщения.

Тексты могут храниться непосредственно в классе исключений, который использует онлайн-репозиторий текстов (OTR), или мы также можем использовать сообщения из класса сообщений (транзакция SE91).

Использование онлайн-репозитория текстов

Следующие шаги помогут вам поддерживать сообщения в классах исключений:

1. На вкладке Атрибуты класса исключений определите атрибут со значением, которое вы хотите передать в сообщении. В этом примере мы поддерживаем MV_CARRID в качестве имени атрибута типа S_CARR_ID, поскольку мы планируем передать краткое название авиакомпании в сообщении об исключении. После определения атрибута нажмите «Активировать».

2. На вкладке «Тексты» сохраните идентификатор исключения и текст. Вы можете передать значение атрибута в сообщении, сохранив имя атрибута между амперсандами (&). Здесь мы сохранили идентификатор исключения как INVALID_CARRID, а текст как Нет данных авиакомпании &MV_CARRID&, заключив атрибут в амперсанды. Вы также можете сохранить длинный текст сообщения, нажав кнопку «Длинный текст». Когда закончите, нажмите Активировать.

3. В этот момент на вкладке «Атрибуты» вы увидите, что определенный идентификатор исключения добавляется как константа типа SOTR_CONC. Поддерживаемый текст сохраняется в OTR и поддерживает интернационализацию (переводы).

4. Конструктор класса автоматически добавляет атрибуты, которые вы добавили в качестве параметров импорта, в свою сигнатуру, которую можно передать при возникновении исключения с помощью ключевого слова EXPORTING. Конструктор гарантирует, что все атрибуты инициализированы правильно. Атрибут textid хранит идентификатор исключения для доступа к соответствующему тексту. Предыдущий атрибут хранит предыдущие исключения в контексте. Ниже показаны сигнатура и код инициализации метода конструктора после добавления атрибута MV_CARRID.

5. Чтобы сгенерировать исключение и передать сообщение с названием авиакомпании, вы можете написать оператор RAISE EXCEPTION, как показано на ниже. Здесь вы вызываете конструктор и передаете TEXTID, обращаясь к константе INVALID_CARRID, определенной в атрибутах класса. Эта константа относится к соответствующему идентификатору исключения. Вы также передаете номер материала атрибуту MV_CARRID, чтобы поле &MV_CARRID& в тексте было заменено значением.

Перехват исключения в программе.

DATA lt_spfli TYPE spfli_tab.
TRY.
    CALL FUNCTION 'Z_TEST_EXCEPTION_EXAMPLE'
      EXPORTING
        iv_id   = 'LR'
      IMPORTING
        et_itab = lt_spfli.
  CATCH zcx_test_exception INTO DATA(lx_msg).
    WRITE / lx_msg->get_text( ).
ENDTRY.

Использование сообщений из класса сообщений

Чтобы использовать сообщения из класса сообщений, выполните следующие действия:

1. Установите флажок «С классом сообщения». Как только этот флажок установлен, система автоматически добавляет к классу сообщений интерфейсы IF_T100_MESSAGE, IF_T100_DYN_MSG, который используется для доступа к сообщениям, хранящимся в классе сообщений.

2.Чтобы использовать сообщение из класса сообщений, перейдите на вкладку «Тексты», сохраните идентификатор исключения и нажмите кнопку «Текст сообщения».

3. В окне «Назначить атрибуты класса исключений сообщению» укажите имя класса сообщений и идентификатор сообщения (номер сообщения). Если вы хотите передать значение атрибута в сообщение, вы можете выбрать атрибут из раскрывающегося списка рядом с каждым полем атрибута. Вы можете передать до четырех атрибутов.

4. Чтобы сгенерировать исключение и передать сообщение с названием авиакомпании, вы можете написать оператор RAISE EXCEPTION.

Перехват исключения в программе.

DATA: lt_spfli TYPE spfli_tab,
      lv_id    TYPE s_carr_id VALUE 'LR'.

DO 2 TIMES.
  TRY.
      CALL FUNCTION 'Z_TEST_EXCEPTION_EXAMPLE'
        EXPORTING
          iv_id   = lv_id
        IMPORTING
          et_itab = lt_spfli.
    CATCH cx_static_check INTO DATA(lx_msg).
      WRITE / lx_msg->get_text( ).
  ENDTRY.
  lv_id = 'AB'.
ENDDO.

Использовали вышестоящий класс исключений cx_static_check, для обоих классов исключений.

Результат:

Использование дополнения MESSAGE для создания исключения

В SAP NetWeaver 7.5 появилось новое дополнение MESSAGE, которое можно использовать при возникновении исключений. Используя дополнение MESSAGE, вы можете передать спецификации сообщения, такие как тип сообщения, идентификатор сообщения и номер сообщения, а также заполнители для сообщения.

Если класс сообщения реализует интерфейс IF_T100_DYN_MSG, вы можете передать тип сообщения, используя дополнение TYPE, а заполнители для сообщения можно передать, используя дополнение WITH. Однако, если класс сообщения реализует интерфейс IF_T100_MESSAGE, то вы не можете передать тип сообщения

и заполнители сообщений, использующие дополнение WITH.

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

В пример показан кода для создания исключения, когда интерфейс IF_T100_DYN_MSG реализован в классе сообщения. В этом примере мы используем дополнение MESSAGE для передачи спецификаций сообщения. Атрибуты и тип сообщения можно передавать напрямую, не определяя их отдельно в классе исключений, поскольку интерфейс IF_T100_DYN_MSG обеспечивает встроенную поддержку.

Понравилась статья? Поделить с друзьями:
  • Ab29 ошибка бмв
  • Ab1d ошибка bmw
  • Ab0b bmw ошибка парктроника
  • Aaff ошибка бмв
  • Aaf9 ошибка бмв парктроники