Содержание
- How To Display Error Messages In SAP ABAP?
- Message Types In ABAP
- DISPLAY LIKE Addition
- Displaying Messages
- Saving Messages In A Variable
- See Also
- ABAP Blog
- Все о разработке в решениях от SAP
- ABAP Blog
- Все о разработке в решениях от SAP
- Ссылки
- Цитаты
- Новое
- Последние комментарии
- Обработка особых ситуаций в ABAP
- Классический способ обработки исключений
- Обработка исключений, основанная на классах
- Категории исключений
- SAP Messages
- SAP Message Classes
- MESSAGE E001(MCLASS).
- Pass message Parameters
- Further information about message types
How To Display Error Messages In SAP ABAP?
An overview of error message types, error and pop-up messages, and how to show messages to the end user.
Published Jun 16, 2021
Message Types In ABAP
In total, ABAP has 6 types of messages.
Type | Description | |
---|---|---|
A | Abend (abnormal end of task) | Displays a message in a dialog pop-up window. The entire transaction is canceled after confirming the message. |
E | Error | Displays an error message in the status line. After confirming the message, the current event block is aborted. |
I | Information | Displays a message in a dialog pop-up window. After confirming the message, the report processing is resumed. |
S | Success / Status | Displays a success message in the status line of the current report. |
W | Warning | Displays a warning message in the status line. After confirming the message, the report processing is resumed. |
X | Exit | Triggers a runtime error and creates a short dump. |
DISPLAY LIKE Addition
As you can see from the previous table the message type can also influence the report execution after the message was confirmed. In case you want to take care of the error handling yourself or simply change the appearance of a message you can use the addition DISPLAY LIKE :
This example prints the message Message text to display in the status line with the red error icon. Since the type itself is S report execution continues normally.
Remember: The addition DISPLAY LIKE only changes the appearance, not the behavior of the message type.
Displaying Messages
Following some examples of how to output a message in ABAP.
Saving Messages In A Variable
The below examples show how to create and store a message in a variable. This can be useful when working with system variables or a message class.
See Also
I’m Dan, a software engineer and consultant passionate about SAP, web and mobile app development.
Источник
ABAP Blog
Все о разработке в решениях от SAP
ABAP Blog
Все о разработке в решениях от SAP
Ссылки
Цитаты
Мы пытаемся решить проблему, максимально ускоряя процесс проектирования, чтобы в конце работы над системой у нас осталось достаточно времени для нахождения ошибок, допущенных из-за слишком быстрого проектирования.
Гленфорд Майерс
Новое
- Получение инстанции cl_gui_alv_grid для SALV 11.09.2021
- Introduction to ABAP in the Cloud 18.08.2021
- Getting Started with FPM BOPF Integration 01.06.2021
- 30. How to Use Authority Checks in Business Object Processing Framework 29.05.2021
- 29. BOPF Extensibility 29.05.2021
- 28. BOPF Enterprise Procurement Model (EPM) 29.05.2021
- 27. BOPF Integration 29.05.2021
- 26. BOPF Business Configuration Objects 29.05.2021
- 25. BOPF Performance 29.05.2021
- 24. BOPF Supportability 29.05.2021
Последние комментарии
Обработка особых ситуаций в ABAP
Когда мы создаем какой-либо многократно используемый компонент, например функциональный модуль или метод в классе, мы сталкиваемся с необходимостью обработки непредвиденных ситуаций (какой-либо входной параметр, оказался не заполненным или доступ к файлу не был получен и т.п.), т.е. тех ситуаций, после которых программа не может выполняться далее стандартным образом, либо требуется дополнительная обработка.
В приведенной статье рассматриваются способы вызова и обработки данных ситуаций, называемых исключениями.
В ABAP есть два основных способа работы с исключениями, классический способ заключается в вызове особых ситуаций описанных в ФМ или методе на отдельной закладке:
Классический способ может использоваться и в классах:
Новый способ основывается на ООП, где в качестве исключений используются классы (обратите внимание, что установлена галочка – классы исключений):
Хочется отметить, что новый способ был введен с версии SAP Web AS 6.10 и при создании новых функциональных модулей или методов рекомендуется использовать именно его. В данной статье не рассматриваются системные исключения и их обработка до введения классов исключений.
В RFC модулях в настоящее время используется классический способ обработки исключений. Не допускается одновременно использовать классический и основанный на классах, способы обработки исключений (в интерфейсе методов, процедур, функций).
Классический способ обработки исключений
При вызове исключения, системное поле sy-subrc будет заполнено номером, под которым исключение было обозначено при вызове ФМ, метода или процедуры:
Как правило, исключения вызываются с текстом сообщения, данный текст может быть описан статически – при вызове исключения оператором MESSAGE, либо динамически – путём получения текста из описания ФМ.
Так же исключение может быть вызвано без какого-либо текста (оператором RAISE ИмяИсключения), но данный способ лучше не использовать, т.к. вызов исключения должен как-то себя расшифровывать и говорить о том, что собственно произошло.
Напишем небольшой ФМ, рассчитывающий сумму двух чисел, оба параметра помечены как необязательные, если первый параметр не будет задан при вызове ФМ, система выдаст исключение – no_num_1.
И программа для его вызова:
При запуске программы произойдет вызов исключения, т.к. был использован тип сообщения «Е», программа завершит свое выполнение после показа сообщения:
Замечу, что это вовсе не означает, что при вызове ФМ или метода и обработке исключения необходимо завершать работу программы, вы можете свободно продолжить её выполнение и далее, добавив например, сообщение об ошибке в лог программы, а не на вывод как в примере.
Ключевое слово OTHERS используется для того чтобы поймать исключения не описанные в ФМ или явно неуказанные, при вызове ФМ.
Пример вызова неописанного исключения:
В данном примере вызывается неописанное в интерфейсе ФМ исключение – no_num_2, которое будет благополучно поймано с помощью ключевого слова OTHERS (системное поле sy-subrc примет значение равное 2).
Кроме того, можно не обрабатывать большой список всех возможных исключений описанных в ФМ, тогда в случае если такое исключение будет вызвано поле sy-subrc примет значение, указанное в OTHERS.
В ФМ, могут быть добавлены новые исключения и в случае, когда при вызове ФМ они не обработаны и не указано слово OTHERS программа упадет в дамп с ошибкой времени выполнения — RAISE_EXCEPTION. Отсюда вывод, ключевое слово OTHERS подставляем всегда, при вызове ФМ (метода или процедуры), когда мы точно не уверены в неизменности компонента.
При вызове исключения в процедурах (perform…) из ФМ, система пытается найти и вызвать исключение в первом ФМ из стека вызовов, если исключение не найдено, вызывается так же, как и неопределенное исключение в ФМ.
Как уже было упомянуто выше, есть возможность получать текст непосредственно из описания особой ситуации:
ФМ будет выглядеть следующим образом:
Результат:
Иногда особые ситуации используются не как исключения, а как параметры показывающие обработку ФМ и его результат, возвращаемый в поле sy-subrc, хотя лучше бы пренебречь подобным стилем:
Сообщения, вызываемые в ФМ или методах, оператором MESSAGE, без дополнения RAISING, либо сообщения вызываемые системой (например, при обработке экранов), могут быть обработаны программой с использованием дополнения: error_message = n_error, указываемого так же после ключевого слова EXCEPTIONS.
При обработке сообщений:
- Сообщения с типом I, W, S не обрабатываются, но записываются в журнал обработки фонового выполнения, если происходит обработка в фоне.
- Сообщения с типом E или A могут быть обработаны, при этом в поле sy-subrc будет записано значение n_error. При вызове сообщения с типом А, происходит вызов ROLLBACK WORK (см. описание оператора MESSAGE).
- Сообщение с типом X не обрабатывается, программа завершается с дампом.
Обработка исключения классическим способом может быть выполнена динамически, с помощью ключевого слова EXCEPTION-TABLE. Пример:
Обработка исключений, основанная на классах
Как понятно из названия, под исключениями в данном случае понимаются объекты специальных классов исключений. Вызов такого исключения может быть выполнен либо в программе с помощью оператора RAISE EXCEPTION, либо системой (например, при делении на ноль будет вызвано предопределённое исключение CX_SY_ZERODIVIDE, список таких исключений), либо через дополнение THROW в условных выражениях (с версии ABAP 7.4).
Во всех случаях инициируется создание объекта указанного класса (если указано дополнение INTO в CATCH), в атрибутах которого содержится информация о возникшей исключительной ситуации, доступ к ним, как правило, осуществляется через методы этого класса.
Классы особых ситуаций могут быть определены как локально, так и глобально через построитель классов – транзакция SE24, диалог создания:
В данном случае галочка «с классом сообщений» означает использование в качестве текста сообщения из класса сообщений транзакция SE91 (будет рассмотрено ниже). По умолчанию текст сообщения создается в текстах класса:
Категории исключений
Все классы особых ситуаций являются производными одного из классов: CX_NO_CHECK, CX_DYNAMIC_CHECK или CX_STATIC_CHECK, которые сами являются производными общего суперкласса CX_ROOT.
- CX_STATIC_CHECK – как правило, исключения которые вызываются в процедуре (ФМ или методе), должны быть либо обработаны в ней, либо процедура должна иметь соответствующий интерфейс, чтобы вызывающий её код мог обработать эту ситуацию. Если исключение определено как потомок этого класса, оно должно быть явно указано в интерфейсе метода (ФМ или формы) в котором происходит его вызов. Данная категория используется тогда, когда в коде явно ожидается передача обработки особой ситуации на уровень выше того места где оно было вызвано. Если при статической проверке, система не увидит обработки в блоке TRY..CATCH..ENDTRY подобного исключения система выдаст предупреждение:
- CX_DYNAMIC_CHECK – при проверке кода, компилятор не будет делать предупреждений об отсутствии обработки исключений их этой категории, в случае вызова исключения его обработка будет проверена динамически и если обработчик не будет найден программа упадет в дамп. Обычно данная категория используется тогда, когда исключение может быть обработано внутри самого метода, без передачи обработки выше по стеку. Примером такой категории может являться исключение вызываемое при делении на ноль, передавать его выше по стеку и указывать в интерфейсе метода вовсе не обязательно, т.к. мы можем его обработать внутри самого метода. Однако, если мы хотим передать обработку данного исключения, необходимо указать его в интерфейсе метода.
- CX_NO_CHECK – аналогичны предыдущему типу, но данную категорию нельзя объявлять в интерфейсах, при этом классы исключений наследуемые от этого класса, неявно все же передаются в интерфейс и выше по стеку вызовов. Данную категорию следует использовать для исключительных ситуаций, которые могут произойти в любое время и не могут быть обработаны непосредственно в коде метода. Кроме того, можно использовать в случаях когда одна и та же исключительная ситуация может возникнуть во множествах методов, а объявлять её в интерфейсах каждого из методов не имеет смысла, т.к. это усложнит код. В итоге подобные исключения могут пройти всю цепочку вызовов методов (т.к. неявно передаются в интерфейс) и быть обработаны на уровне программы.
На исключения накладываются следующие ограничения:
- Исключение не может быть объявлено в интерфейсе статического конструктора:
- Исключение не может быть объявлено в интерфейсе обработчика событий. При этом если в коде обработчика произошел вызов исключения, и он не был обработан, система вызовет исключение — CX_SY_NO_HANDLER, которое может быть обработано в вызывающем его коде.
- При вызове программ через SUMBIT или CALL TRANSACTION, исключение, возникающее в вызываемой программе, не может быть передано в вызывающую программу.
Небольшой пример с локальным классом исключения:
Источник
SAP Messages
A SAP message is an essential part of any ABAP program and are used to display information to the user to let them know what’s happening. This could be in a number of ways such as an error message, warning message or information message.
The following ABAP code is the simplest way to implement a message into your report.
MESSAGE ‘Display this message’ TYPE ‘E’.
SAP Message Classes
A better way to implement your messages would be to create and maintain them via a message class using transactions SE91 or SE80. This way you have a central store for all messages, which makes it easier to maintain. This is especially true if your messages need to be translated into multiple languages. Enter your text here.
To do this you first need to create a message class which is a kind of container/wrapper where you store related messages together. Once this is done you can add as many message as you require into it. You also get the option to create additional long text, which offers the user additional information about the particular issue. See the following link for more information and details of how to create a message class.
Once you have created your message you can use them within your ABAP code using the following syntax:
MESSAGE E001(MCLASS).
MESSAGE = ABAP statement
E = Type of message (can also be I,W,S,A,X)
001 = Message number
MCLASS = Message Class
Pass message Parameters
You can also add parameters to your messages using the «&» character. So for example you could create the following message ‘Purchase order & has been deleted’. You can then pass a purchase order number to the message when using it and it will replace the «&» with the purchase order you pass for example
MESSAGE E001(MCLASS) with ekko-ebeln.
The result would display
«Purchase order 1234 has been deleted»
Further information about message types
I — Information messages
Information message are displayed in a popup window and only pause processing until you have clicked through the message.
E — Error message
An error message will be displayed in red along the footer of the SAP screen and stops processing going any further.
W — Warning message
A warning message behaves similar to and error message and is displayed along the footer of the SAP screen and stops processing going any further.
S — Success/Status message
A Success message is also displayed along the footer of the SAP screen but does not stop processing going any further and is simply displayed at the end in green.
A — Termination/Abend
A termination message stops processing and causes a runtime error and short dump which is also viewable in tcode ST22.
X — Exit
An exit message stops processing and displays and exit button which exits session processing. Similar to typing /n into the SAP command box.
Источник
Когда мы создаем какой-либо многократно используемый компонент, например функциональный модуль или метод в классе, мы сталкиваемся с необходимостью обработки непредвиденных ситуаций (какой-либо входной параметр, оказался не заполненным или доступ к файлу не был получен и т.п.), т.е. тех ситуаций, после которых программа не может выполняться далее стандартным образом, либо требуется дополнительная обработка.
В приведенной статье рассматриваются способы вызова и обработки данных ситуаций, называемых исключениями.
В ABAP есть два основных способа работы с исключениями, классический способ заключается в вызове особых ситуаций описанных в ФМ или методе на отдельной закладке:
Классический способ может использоваться и в классах:
Новый способ основывается на ООП, где в качестве исключений используются классы (обратите внимание, что установлена галочка – классы исключений):
Хочется отметить, что новый способ был введен с версии 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 sy—subrc <> 0. MESSAGE ID sy—msgid TYPE sy—msgty NUMBER sy—msgno WITH sy—msgv1 sy—msgv2 sy—msgv3 sy—msgv4. ENDIF. WRITE gv_summ. |
При запуске программы произойдет вызов исключения, т.к. был использован тип сообщения «Е», программа завершит свое выполнение после показа сообщения:
Замечу, что это вовсе не означает, что при вызове ФМ или метода и обработке исключения необходимо завершать работу программы, вы можете свободно продолжить её выполнение и далее, добавив например, сообщение об ошибке в лог программы, а не на вывод как в примере.
Ключевое слово 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 подставляем всегда, при вызове ФМ (метода или процедуры), когда мы точно не уверены в неизменности компонента.
При вызове исключения в процедурах (perform…) из ФМ, система пытается найти и вызвать исключение в первом ФМ из стека вызовов, если исключение не найдено, вызывается так же, как и неопределенное исключение в ФМ.
Как уже было упомянуто выше, есть возможность получать текст непосредственно из описания особой ситуации:
ФМ будет выглядеть следующим образом:
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 funct—funcname, lv_exc TYPE funct—parameter, lv_txt TYPE swotlq—shorttext. lv_fun = ‘ZTEST_EXC’. lv_exc = ‘NO_NUM_1’. CALL FUNCTION ‘SWO_TEXT_FUNCTION_EXCEPTION’ EXPORTING language = sy—langu 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. |
Результат:
Иногда особые ситуации используются не как исключения, а как параметры показывающие обработку ФМ и его результат, возвращаемый в поле 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 sy—subrc. WHEN 1. WRITE ‘More 10’. WHEN 2. WRITE ‘Less 10’. WHEN 3. WRITE ‘Equal |
Результат:
Сообщения, вызываемые в ФМ или методах, оператором 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 sy—subrc = 1. WRITE ‘ФМ вызвал MESSAGE с типом E,A’. ENDIF. |
Результат:
Обработка исключения классическим способом может быть выполнена динамически, с помощью ключевого слова 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_line—name = ‘FILENAME’. ptab_line—kind = abap_func_exporting. GET REFERENCE OF filename INTO ptab_line—value. INSERT ptab_line INTO TABLE ptab. ptab_line—name = ‘FILETYPE’. ptab_line—kind = abap_func_exporting. GET REFERENCE OF filetype INTO ptab_line—value. INSERT ptab_line INTO TABLE ptab. ptab_line—name = ‘DATA_TAB’. ptab_line—kind = abap_func_tables. GET REFERENCE OF text_tab INTO ptab_line—value. INSERT ptab_line INTO TABLE ptab. ptab_line—name = ‘FILELENGTH’. ptab_line—kind = abap_func_importing. GET REFERENCE OF fleng INTO ptab_line—value. INSERT ptab_line INTO TABLE ptab. ... etab_line—name = ‘OTHERS’. etab_line—value = 10. INSERT etab_line INTO TABLE etab. CALL FUNCTION func PARAMETER—TABLE ptab EXCEPTION—TABLE etab. CASE sy—subrc. WHEN 1. ... ... ENDCASE. |
Обработка исключений, основанная на классах
Как понятно из названия, под исключениями в данном случае понимаются объекты специальных классов исключений. Вызов такого исключения может быть выполнен либо в программе с помощью оператора RAISE EXCEPTION, либо системой (например, при делении на ноль будет вызвано предопределённое исключение CX_SY_ZERODIVIDE, список таких исключений), либо через дополнение THROW в условных выражениях (с версии ABAP 7.4).
Во всех случаях инициируется создание объекта указанного класса (если указано дополнение INTO в CATCH), в атрибутах которого содержится информация о возникшей исключительной ситуации, доступ к ним, как правило, осуществляется через методы этого класса.
Классы особых ситуаций могут быть определены как локально, так и глобально через построитель классов – транзакция SE24, диалог создания:
В данном случае галочка «с классом сообщений» означает использование в качестве текста сообщения из класса сообщений транзакция SE91 (будет рассмотрено ниже). По умолчанию текст сообщения создается в текстах класса:
Категории исключений
Все классы особых ситуаций являются производными одного из классов: CX_NO_CHECK, CX_DYNAMIC_CHECK или CX_STATIC_CHECK, которые сами являются производными общего суперкласса CX_ROOT.
- CX_STATIC_CHECK – как правило, исключения которые вызываются в процедуре (ФМ или методе), должны быть либо обработаны в ней, либо процедура должна иметь соответствующий интерфейс, чтобы вызывающий её код мог обработать эту ситуацию. Если исключение определено как потомок этого класса, оно должно быть явно указано в интерфейсе метода (ФМ или формы) в котором происходит его вызов. Данная категория используется тогда, когда в коде явно ожидается передача обработки особой ситуации на уровень выше того места где оно было вызвано. Если при статической проверке, система не увидит обработки в блоке TRY..CATCH..ENDTRY подобного исключения система выдаст предупреждение:
- CX_DYNAMIC_CHECK – при проверке кода, компилятор не будет делать предупреждений об отсутствии обработки исключений их этой категории, в случае вызова исключения его обработка будет проверена динамически и если обработчик не будет найден программа упадет в дамп. Обычно данная категория используется тогда, когда исключение может быть обработано внутри самого метода, без передачи обработки выше по стеку. Примером такой категории может являться исключение вызываемое при делении на ноль, передавать его выше по стеку и указывать в интерфейсе метода вовсе не обязательно, т.к. мы можем его обработать внутри самого метода. Однако, если мы хотим передать обработку данного исключения, необходимо указать его в интерфейсе метода.
- CX_NO_CHECK – аналогичны предыдущему типу, но данную категорию нельзя объявлять в интерфейсах, при этом классы исключений наследуемые от этого класса, неявно все же передаются в интерфейс и выше по стеку вызовов. Данную категорию следует использовать для исключительных ситуаций, которые могут произойти в любое время и не могут быть обработаны непосредственно в коде метода. Кроме того, можно использовать в случаях когда одна и та же исключительная ситуация может возникнуть во множествах методов, а объявлять её в интерфейсах каждого из методов не имеет смысла, т.к. это усложнит код. В итоге подобные исключения могут пройти всю цепочку вызовов методов (т.к. неявно передаются в интерфейс) и быть обработаны на уровне программы.
На исключения накладываются следующие ограничения:
- Исключение не может быть объявлено в интерфейсе статического конструктора:
- Исключение не может быть объявлено в интерфейсе обработчика событий. При этом если в коде обработчика произошел вызов исключения, и он не был обработан, система вызовет исключение — 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). Константы идентификаторы, представленные в шестнадцатеричном формате, уникальны на уровне системы:
Доступ к хранилищу текстов можно получить через транзакцию SOTR_EDIT.
В текстах можно определить параметры, их необходимо обозначить в амперсандах. В качестве примера, можно рассмотреть текст из класса исключения — CX_SY_FILE_IO:
В параметры будут переданы (при вызове метода GET_TEXT) соответствующие им атрибуты класса:
Заполняются эти атрибуты в конструкторе при вызове исключения:
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.
Блок 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):
Просмотр ошибки в транзакции 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 хранит в себе эти сообщения):
При редактировании текста, необходимо будет привязать его к классу и номеру сообщения, при этом заполнить параметры, если это необходимо:
Начиная с NW 2004, оператор MESSAGE позволяет напрямую обработку исключений, внедряющих интерфейс IF_T100_MESSAGE:
TRY. ... CATCH cx_some_exception INTO lr_ex. MESSAGE lr_ex TYPE ‘E’. ENDTRY. |
Локальный класс исключения в приватном методе глобального класса
Бывают ситуации, когда для какого-либо приватного метода необходимо реализовать исключение, которое может быть вызвано исключительно данным методом (классом). Реализовать подобное можно, если создать локальный класс исключений:
- Перейти в локальные определения/внедрения:
- Создать класс исключения:
- Указать в методе имя локального класса исключения (обязательно в режиме редактирования исходного кода):
Результат:
Если попробовать сделать тоже самое в режиме редактирования на основе формуляров, выскочит предупреждение о том, что такого класса не существует:
Более подробно об исключениях можно почитать в официальной документации:
http://help.sap.com/abapdocu_740/en/abenabap_exceptions.htm
Оператор MESSAGE служит для диалогового взаимодействия с пользователем. Существует шесть типов сообщения.
Тип | Описание |
---|---|
S | Status (Success). Сообщение отображается в статусной строке и не влияет на работу программы. Данный вид сообщения применяется для информирования об успешной выполнении операции. |
W | Warning. Предупредительные сообщения отображаются в статусной строке. При возникновении сообщения работа программы прерывается, а пользователю предоставляется возможность вносить исправления в полях для ввода. При нажатии на Enter в диалоговом режиме, работа программы будет восстановлена. |
E | Error. Сообщение отображается в статусной строке. При возникновении данного вида сообщения обработка программы останавливается. |
I | Information. Информационное сообщение отображается в отдельном модальном окне. При возникновении сообщения работа программы прерывается. После закрытия диалога работа программы восстанавливается. |
A | Abend (Abort). Сообщение отображается в модальном окне. При возникновении сообщения программа завершается, а система возвращается в меню более высокого уровня. Сообщения стоит применять только в крайних ситуациях. |
X | Exception. Сообщение инициирует дамп MESSAGE_TYPE_X. Данный вид сообщения стоит применять в ситуациях, когда нужно проанализировать что именно привело к ошибке во время выполнения. |
Синтаксис
MESSAGE { msg | text | exception }
{ { [DISPLAY LIKE dtype] [WITH dobj1 … dobj4] }
| { [DISPLAY LIKE dtype] [WITH dobj1 … dobj4] RAISING exception }
| { [WITH dobj1 … dobj4] INTO text } }.
После вызова оператора MESSAGE заполняются системные поля
Поле | Значение |
---|---|
sy-msgid | Содержит класс сообщения |
sy-msgno | Содержит номер сообщения |
sy-msgty | Содержит тип сообщения (S,I,W,E,A,X) |
sy-msgv1 .. sy-msgv4 | Содержит данные сообщения, указанные после добавления WITH |
Для вывода сообщений используются классы сообщений, которые создаются в тр. SE91
MESSAGE — msg
При выводе сообщений нужно указать: класс, номер и тип сообщения
MESSAGE tn(id)
MESSAGE tn
MESSAGE ID mid TYPE mtype NUMBER num.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
*&———————————————————————* *& Report Z_MESSAGE *& Возможности оператора MESSAGE *&———————————————————————* *& Примеры использования оператора MESSAGE *& http://abap4.ru/?p=360 *&———————————————————————* REPORT z_message MESSAGE-ID 00. START-OF-SELECTION. PERFORM main. FORM main. » Краткая запись MESSAGE s002(00). » Краткая запись. Класс сообщения указывается в MESSAGE-ID программы MESSAGE s002. » Полная запись с указанием класса, типа и номера в отдельных полях MESSAGE ID ’00’ TYPE ‘S’ NUMBER ‘002’. ENDFORM. |
Результат работы программы
MESSAGE — text
MESSAGE text TYPE mtype.
В также MESSAGE можно передать свободный текст. В этом случае класс сообщения будет 00, номер сообщения 001. Данный вариант обычно используют когда нет возможности определить сообщения в SAP, например когда текст сообщения формируется во внешних системах.
*&———————————————————————* *& Пример вывода текста *& http://abap4.ru/?p=360 *&———————————————————————* REPORT z_message. START-OF-SELECTION. PERFORM main. FORM main. MESSAGE ‘Текст сообщения’ TYPE ‘I’. ENDFORM. |
Результат работы программы
В системных полях будет сообщение базисного класса 001(00)
MESSAGE — exception
MESSAGE oref TYPE mtype.
В также MESSAGE можно передать исключение. Результат будет аналогичен выводу исключения.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
*&———————————————————————* *& Пример вывода исключения *& http://abap4.ru/?p=360 *&———————————————————————* REPORT z_message. START-OF-SELECTION. PERFORM main. FORM main. DATA lr_root TYPE REF TO cx_root. DATA lv_value TYPE i. TRY . lv_value = 1 / 0. CATCH cx_root INTO lr_root. MESSAGE lr_root TYPE ‘I’. ENDTRY. ENDFORM. |
Результат работы программы
Значения системных полей
MESSAGE — WITH
MESSAGE … WITH dobj1 … dobj4.
Сообщения могут содержать параметры, которые передаются через дополнение WITH. Пример вывода сообщения 076(va) с двумя параметрами.
*&———————————————————————* *& Вывод сообщения с параметрами *& http://abap4.ru/?p=360 *&———————————————————————* REPORT z_message. START-OF-SELECTION. PERFORM main. FORM main. MESSAGE i076(va) WITH ‘TESTVAR’ sy—repid. ENDFORM. |
Результат работы программы
MESSAGE — DISPLAY LIKE
MESSAGE … DISPLAY LIKE dtype.
При использовании дополнения DISPLAY LIKE, происходит замена иконки на специфичную для типа, указанного в dtype. В dtype можно передать одно из следующих значений: A, E, I, S или W. Данное дополнение нельзя использовать для сообщения типа X, оно всегда вызывает дамп. DISPLAY LIKE обычно используется в ситуациях, когда нужно отобразить ошибку, но не прерывать выполнение программы.
*&———————————————————————* *& Пример использования DISPLAY LIKE *& http://abap4.ru/?p=360 *&———————————————————————* REPORT z_message. START-OF-SELECTION. PERFORM main. FORM main. MESSAGE ‘Ошибка в модальном окне’ TYPE ‘I’ DISPLAY LIKE ‘E’. ENDFORM. |
Результат работы программы
MESSAGE — INTO
MESSAGE … INTO text.
При использовании дополнения INTO, в переменную text записывается короткий текст сообщения. Само сообщение при этом, не отображается. Данное дополнение обычно применяют в двух случаях: когда нужно получить текст сообщения; когда нужно заполнить системные переменные для дальнейшего использования, например, для журнала приложений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
*&———————————————————————* *& Пример использования MESSAGE INTO *& http://abap4.ru/?p=360 *&———————————————————————* REPORT z_message. START-OF-SELECTION. PERFORM main. FORM main. DATA lv_text TYPE text120. MESSAGE e036(60) WITH ‘2100’ INTO lv_text. » Балансовая единица «&» неизвестна (ввести существующую БЕ). WRITE: / ‘TEXT: ‘, lv_text. WRITE: / ‘SY-MSGID: ‘, sy—msgid. WRITE: / ‘SY-MSGTY: ‘, sy—msgty. WRITE: / ‘SY-MSGNO: ‘, sy—msgno. WRITE: / ‘SY-MSGV1: ‘, sy—msgv1. WRITE: / ‘SY-MSGV2: ‘, sy—msgv2. WRITE: / ‘SY-MSGV3: ‘, sy—msgv3. WRITE: / ‘SY-MSGV4: ‘, sy—msgv4. ENDFORM. |
MESSAGE — RAISING
MESSAGE … RAISING exception.
Оператор MESSAGE вместе с дополнением RAISING представляет собой комбинацию операторов MESSAGE и RAISE. Данное дополнение имеет смысл только во время обработки методов и функциональных модулей, в которых определено исключение старого типа (основанного не на классах). Если вызывающий метод или функциональный модуль обрабатывает данное исключение в EXCEPTIONS, то MESSAGE .. RAISING работает аналогично оператору RAISE. Если же вызывающей стороне исключение не обрабатывается, то RAISING игнорируется.
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 |
*&———————————————————————* *& Пример использования MESSAGE RAISING *& http://abap4.ru/?p=360 *&———————————————————————* REPORT z_message. CLASS c1 DEFINITION. PUBLIC SECTION. CLASS-METHODS m1 EXCEPTIONS exc1. ENDCLASS. CLASS c1 IMPLEMENTATION. METHOD m1. MESSAGE ‘Сообщение с RAISING’ TYPE ‘I’ RAISING exc1. ENDMETHOD. ENDCLASS. START-OF-SELECTION. PERFORM main. FORM main. c1=>m1( ). » Отработает MESSAGE c1=>m1( EXCEPTIONS exc1 = 4 ). » Отработает RAISING IF sy—subrc = 4. ENDIF. ENDFORM. |
Preface – This post is part of the ABAP Beginner series.
Introduction
A programmer always tries to code in such a way that his code is bug free and full proof. But there are certain scenarios, where his codes can fail. In such case, if the coder already knows the scenarios, then he handle them in form of Error handling. But, in case of situations, where an error can be generated due to unknown situations and left un-handled can cause serious dumps. For these scenarios, we have exception handling in SAP. In this article we will explore all scenarios of Exception and Error Handling in ABAP Reports
Exception and Error Handling in SAP ABAP Reports
As discussed above, a coder is required to handle known issues as well as intended error messages. These messages are shown to user in the output via MESSAGE statement.
Different ways to catch Errors/Exception
ABAP provides various ways to catch errors in an ABAP program.
-
Using System Variable
The simplest way is to use their system variables.
SY-SUBRC EQ 0. "This statement indicates that an operation completed successfully. SY-SUBRC NE 0. "This statement indicates that an operation has failed.
This way works directly if the entire code of report was process within the same program. It means, it cannot catch an error directly in case you have processed a Function Module or ABAP Class statements. For those entity, we need to raise exception from their end, and then exception can be handled in the report and processed accordingly.
-
Catching Errors based on Exception
In case, we implement a function module or method of a class, then it is important to raise exception from these classes and then we can catch these exceptions in report and show respective error.
For Example:
CALL FUNCTION 'Test_Function' EXPORTING DELIMITER = ':' STRING = lv_string IMPORTING HEAD = lv_head TAIL = lv_tail EXCEPTIONS NOT_FOUND = 1 OTHERS = 2. CASE SY-SUBRC. WHEN 1. ... // Show Error Message WHEN 2. ... // Show Error Message WHEN OTHER. // Show Error Message ENDCASE.
-
Using TRY CATCH ENDTRY
In case an exception is raised via a method of class, or an unexpected exception is raised, in these cases, we use TRY CATCH functionality of SAP ABAP. This is one of the best full proof way to handle all types of exceptions.
Example:
TRY. //Call your class or function module here CATCH CX_SY_ZERODIVIDE INTO O_REF. // The exception you have raised there MESSAGE “Your Error Message”. ENDTRY.
Different ways to show Messages
-
Using ABAP Statement
Syntax:
MESSAGE ‘<Enter Your Text here>’ TYPE ‘Enter the type of Message here’.
Types of Message
ABAP provides the following 6 types of messages:
Message Type | Meaning | Explanation |
A | Termination | This message is shown during program termination. |
E | Error | This message is shown during Error. |
I | Information | This message is used to show any information. |
S | Success | This shown in the status of the Output screen. |
W | Warning | It behaves like an error message. |
X | Exit | It causes a short dump with error message. |
-
Using Predefined Function Modules
ABAP provides following function modules that can be used to store, format and show messages altogether:
Function Module | Usage |
MESSAGES_INITIALIZE | To Initialize the messages. |
MESSAGE_STORE | To Store the messages to be displayed. |
MESSAGES_SHOW | To Display all the messages together on a pop up |
FORMAT_MESSAGE | To Format the messages |
HR_DISPLAY_ERROR_LIST | To display all the error messages |
Example:
- Using Message Statement
MESSAGE 'This is an error message' TYPE 'E'.
- Using Multiple functions to store and show messages:
" It is Initialized only initially... * Initialize your messages CALL FUNCTION 'MESSAGES_INITIALIZE' EXCEPTIONS log_not_active = 1 wrong_identification = 2 OTHERS = 3. "One by one append all your messages here PERFORM store_messages USING 'E' w_pn w_batch2 w_werks ' ' w_msgno. FORM store_messages USING p_msgty p_msgv1 p_msgv2 p_msgv3 p_msgv4 p_txtnr. IF p_msgty EQ 'E'. w_err_fg = 'X'. ENDIF. * Store all your messages meant to be displayed CALL FUNCTION 'MESSAGE_STORE' EXPORTING arbgb = 'ZCCH001' msgty = p_msgty msgv1 = p_msgv1 msgv2 = p_msgv2 msgv3 = p_msgv3 msgv4 = p_msgv4 txtnr = p_txtnr EXCEPTIONS message_type_not_valid = 1 not_active = 2 OTHERS = 3. ENDFORM. " STORE_MESSAGES "In the end fetch all your message and show them altogether * This displays all the messages in a popup CALL FUNCTION 'MESSAGES_SHOW' EXPORTING show_linno = ' ' IMPORTING e_exit_command = wa_exit_command EXCEPTIONS inconsistent_range = 1 no_messages = 2 OTHERS = 3.
- Using HR_DISPLAY_ERROR_LIST
DATA: it_error TYPE STANDARD TABLE OF HRERROR,"TABLES PARAM wa_error LIKE LINE OF it_error . DATA(ld_no_popup) = 'some text here'. DATA(ld_no_print) = 'some text here'. DATA(ld_no_img) = 'some text here'. DATA(ld_no_msgno) = 'some text here'. DATA(ld_linesize) = '123 '. DATA(ld_listheader) = 'Check type of data required'. DATA(ld_colheader) = 'Check type of data required'. DATA(ld_hidemsg) = 'some text here'. "populate fields of struture and append to itab append wa_error to it_error. . CALL FUNCTION 'HR_DISPLAY_ERROR_LIST' * EXPORTING * no_popup = ld_no_popup * no_print = ld_no_print * no_img = ld_no_img * no_msgno = ld_no_msgno * linesize = ld_linesize * listheader = ld_listheader * colheader = ld_colheader * hidemsg = ld_hidemsg * TABLES * error = it_error EXCEPTIONS INVALID_LINESIZE = 1 . " HR_DISPLAY_ERROR_LIST IF SY-SUBRC EQ 0. "All OK ELSEIF SY-SUBRC EQ 1. "Exception "Add code for exception here ENDIF.
How to create SAP ABAP Error Message Class
SAP ABAP Error Messages are very important for each ABAP program to know what is happening in that Program. Creating an error message class is very easy and we can create message classes using SE91 and SE38 Transaction codes.
Every Message has the message class and its ID and its Type.
Message Class in SAP ABAP
MESSAGE E001(MCLASS).
MESSAGE-Keyword
E-Message Type
001-Message Id
Mclass-Message class Name
Message Class TCode
SE91 and SE38 are message classTransaction codes.
Creating Message Class in SAP ABAP
First of all, Go to SE91 Tcode and Give the Message Class Name ZDEMO_MESSAGE and click on create
In the Messages Tab, choose id and enter Message Description.
Message Class has been created successfully. Now how to use created message class in the ABAP program.
MESSAGE I000(ZDEMO_MESSAGE).
Types of Messages in SAP ABAP
I — Information messages
Information messages are displayed in a popup window and only pause processing until you have clicked through the message.
E — Error message
An error message will be displayed in red along the footer of the SAP screen and stops processing going any further.
W — Warning message
A warning message behaves similar to an error message and is displayed along the footer of the SAP screen.
S — Success/Status message
A Success message is also displayed along the footer of the SAP screen but does not stop processing going any further and is simply displayed at the end in green.
A — Termination/Abend
A termination message stops processing and causes a run time error and short dump.
X — Exit
An exit message stops processing and displays an exit button which exits session processing.
How many ways can we display the messages in the SAP ABAP Program
a). MESSAGE ‘abs’ type ‘I’.
b). MESSAGE I003 (<Message Class>)
c). REPORT <Program Name> MESSAGE-ID <Message Class>.
MESSAGE I006.
d). MESSAGE text-001 type ‘I’.
e). MESSAGE i009 WITH ‘create the correct sales order number'(003).
f). MESSAGE ID ‘<Message Class>’ type ‘I’ NUMBER 002.
g). MESSAGE i007 (<Message Class>) WITH ‘<Some text message> ‘.
h). MESSAGE i004 WITH text-003.
i). MESSAGE i002 (<Message Class>) WITH text-003.
j). MESSAGE i002 (<Message Class>) with p_user.
message class in sap abap |
how to create message class in sap abap |
message class tcode |
message class |
how to use message class in sap abap |
create message class in sap abap |
sap message class |
message class in sap |
sap message class tcode |
tcode for message class |
message class tcode in sap |
tcode for message class in sap |
message class tcode in sap abap |
sap tcode message class |
abap message class tcode |
abap message class |
sap create message class |
message class in abap |
tcode message class |
how to create a message class in sap abap |
message class in sap abap tcode |
tcode for message class in sap abap |
sap transaction message class |
message class abap |
abap create message class |
abap message |
sap tcode for message class |
standard message class in sap abap |
transaction for message class in sap |
message class sap |
sap abap message class |
message class transaction sap |
message class tcode sap |
message class sap tcode |
sap message class table |
message abap |
abap error message |
abap message example |
sap message class transaction |
message class table in sap |
how to write error message in sap abap |
abap message id |
se91 in sap |
error message in sap abap |
error message abap |
sap abap message |
message to class |
sap message id tcode |
se91 tcode in sap |
sap abap error message |
display error message in sap abap |
sap change error message to warning |
abap message types |
sap abap message types |
how to check message class in sap |
how to display error message in sap abap |
types of messages in sap abap |
se91 sap |
message types in sap abap |
sap display message class |
sap standard message class with |
error message syntax in sap abap |
sap abap message example |
how to display multiple error messages in sap abap |
message in sap abap |
warning message in sap abap |
abap text-001 |
messages in abap |
abap class tcode |
message with abap |
se91 |
how to find message class in sap |
sap se91 |
Popular posts from this blog
BADI Interview Questions in SAP ABAP
BADI Interview Questions in SAP ABAP A BAdI is an object-oriented enhancement option, which makes it the most sophisticated enhancement type. The main characteristic of a BAdI is that it provides a mechanism to change the functionality of a well-defined business function without making changes to the delivered source code. Future upgrades of the original business function can be applied without losing the customer-specific enhancements or the need to merge the changes. If you want to become a professional and technical blogger practically, read these real-world practical SAP ABAP books . These books will help you to become a more flexible coding developer in future SAP technology. What is a BADI in SAP? BADI (Business Add-In) is a new SAP Object Oriented enhancement technique that is used to add our own business functionality to the existing SAP standard functionality. BADI follows the Object-Oriented approach to make them reusable. A BADI can be used any number of times
Sample SAP ABAP Programming Examples for Practice
Sample SAP ABAP Programming Examples for Practice Are you a beginner at ABAP Language, you’re looking for example programs for practice. Here I collected some sample programs from various objects in ABAP that are useful for beginners to improve their Technical skills. To familiar with coding and ABAP applications, you must be practice all applications. As per my experience, practice makes you perfect, as a technical consultant, should be ready to develop any object based on the need of the client, then only, we will get appreciation from the client and from our team side and it helps us to develop complex objects in SAP. ABAP Syntax ABAP Statements ABAP Program Types SAP ABAP Workbench Tools SAP Modules SAP Transaction Codes SAP Tables SAP ABAP Hello world Program Example ABAP- Simple ALV report Example ABAP- Interactive ALV Report Example ABAP- BDC Call Transaction Method Programming ABAP- BDC Session Method Programming Example ABAP- Smartforms
Module Pool Programming Interview Questions and Answers in SAP ABAP
Module Pool Programming(Dialog Programming) Interview Questions and Answers in SAP ABAP As an ABAP Consultant, you should be strong in Module pool programming techniques as well as when you face the real-time or fresher interview, Questions, and answers to test your talent to select for the interview. For that purpose, I am sharing my interview experiences in which I faced the most of the times on these topics that are at exit command, events difference between set screen and call screen difference between call screen and set screen in module pool,chain-end chain in module pool. What is the transaction code for the screen painter? SE51. What is the transaction code for Menu painter? SE41. What is the transaction code for the screen painter? SE93. What are the main components of dialog programs? Screens Module pools Subroutines Menus Transactions What is Screen flow Logic? The screen flow logic is like an ABAP program in that it serves as a
Step by Step tutorial on BDC Session Method Program in SAP ABAP
Step by Step tutorial on BDC Session Method Program in SAP ABAP BDC Session Method is used to upload data from Non-SAP to SAP System. Using Session method, we can transfer data through more than one Transaction, Unlike BDC Call Transaction Method Program . We are Processing Batch input Session From SM35 Transaction Code. Session method. 1) synchronous processing. 2) can transfer a large amount of data. 3) processing is slower. 4) error log is created 5) data is not updated until the session is processed. Call transaction Method. 1) asynchronous processing 2) can transfer a small amount of data 3) processing is faster. 4) errors need to be handled explicitly 5) data is updated automatically Go to SHDB and Press Enter Click on New Recording Button and Give the zrecord1 name and enter transaction code MM01 and click on the Start recording button. The system goes to the Create material screen, there give the industry sector and material type and selects ba
SAP ABAP Interview Questions and Answers for 10 Years Experienced
SAP ABAP Interview Questions and Answers for 10 Years Experienced This post will helpful for SAP ABAP experienced candidates who may have 3,4 5, 6,7, and 10 years of experience, all of them can be follow this interview pattern for their successful interview. SAP Data Dictionary Realtime Interview Questions SAP BDC Realtime Interview Questions SAP ALV Reports Real-time Interview Questions Module Pool Interview Questions SAP Smartforms Realtime Interview Questions SAP BADI Realtime Interview Questions SAP BAPI Realtime Interview Questions SAP IDOC Realtime Interview Questions ABAP Check and Value Table Questions SAP SD MM FICO Flow Interview Questions SAP OOPs Realtime Interview Questions SAP OOPs Part One Real-time Interview Questions SAP OOPs Part two Real time Interview Questions SAP OOPs Part three Realtime Interview Questions SAP OOPs Part four Realtime Interview Questions ABAP Realtime Interview Questio
What is Message?
Messages are used to describe what is happening in the program execution to the programmer or user. Messages represents with a three-digit number. Messages range starts from 000 to 999.
Message Types —
Messages are basically six types. Those are —
A | Abend | The message appears in a separate dialog box and the program execution get terminated. When the user has confirmed the message, control returns to the next-highest area menu. |
E | Error | An error dialog appears or the program terminates depending on the program condition. |
I | Information | The message appears in a separate dialog box. Once the user has confirmed the message, the program execution continues from the next statement coded immediately after the MESSAGE statement. |
S | Success | The total program execution continues normally and the message is displayed in the status bar of the screen. |
W | Warning | An error message is displayed in the status bar of the screen and the program execution terminates. |
X | Exit or Abort | No message is displayed. The program terminates with a short dump. Program terminations with a short dump normally only occur when a runtime error occurs. |
Message Usage —
Messages can be added to the program mostly in two ways. Those are —
- Coding directly in the program
- By using the message class.
Coding directly in the program —
Coding the message directly in the program is a very simple process. No definition was required before coding the message in the program.
Syntax —
MESSAGE {message-name} TYPE {message-type}.
- Message — 80 characters user defined message.
- Message-type — Specifies the message type.
Now, let us see how different message types coded one by one with seperate examples.
Example —
Display abend message.
Code —
*&---------------------------------------------------------------------*
*& Report Z_MESSAGE
*&---------------------------------------------------------------------*
*& Written by TutorialsCampus
*&---------------------------------------------------------------------*
REPORT Z_MESSAGE.
* Displaying Abend Message of type A
MESSAGE 'This is a Abend message' TYPE 'A'.
Output —
Explaining Example —
In the above example, each and every statement is preceeded with a comment to explain about the statement. Go through them to get clear understanding of example code.
MESSAGE ‘This is a Abend message’ TYPE ‘A’. — Opens a popup and displays ‘This is a Abend message’ on the popup.
Example —
Display error message.
Code —
*&---------------------------------------------------------------------*
*& Report Z_MESSAGE
*&---------------------------------------------------------------------*
*& Written by TutorialsCampus
*&---------------------------------------------------------------------*
REPORT Z_MESSAGE.
* Displaying error Message of type E
MESSAGE 'This is a Error message' TYPE 'E'.
Output —
Explaining Example —
In the above example, each and every statement is preceeded with a comment to explain about the statement. Go through them to get clear understanding of example code.
MESSAGE ‘This is a Error message’ TYPE ‘E’. — Displays ‘This is a Error message’ on the output page status bar.
Example —
Display Informational message.
Code —
*&---------------------------------------------------------------------*
*& Report Z_MESSAGE
*&---------------------------------------------------------------------*
*& Written by TutorialsCampus
*&---------------------------------------------------------------------*
REPORT Z_MESSAGE.
* Displaying Informational Message of type I
MESSAGE 'This is a Informational message' TYPE 'I'.
Output —
Explaining Example —
In the above example, each and every statement is preceeded with a comment to explain about the statement. Go through them to get clear understanding of example code.
MESSAGE ‘This is a Informational message’ TYPE ‘I’. — Opens a popup and displays ‘This is a Informatonal message’ on the popup.
Example —
Display success message.
Code —
*&---------------------------------------------------------------------*
*& Report Z_MESSAGE
*&---------------------------------------------------------------------*
*& Written by TutorialsCampus
*&---------------------------------------------------------------------*
REPORT Z_MESSAGE.
* Displaying Success Message of type S
MESSAGE 'This is a Success message' TYPE 'S'.
Output —
Explaining Example —
In the above example, each and every statement is preceeded with a comment to explain about the statement. Go through them to get clear understanding of example code.
MESSAGE ‘This is a Success message’ TYPE ‘S’. — Displays ‘This is a Success message’ on the output page status bar.
Example —
Display warning message.
Code —
*&---------------------------------------------------------------------*
*& Report Z_MESSAGE
*&---------------------------------------------------------------------*
*& Written by TutorialsCampus
*&---------------------------------------------------------------------*
REPORT Z_MESSAGE.
* Displaying Warning Message of type W
MESSAGE 'This is a Warning message' TYPE 'W'.
Output —
Explaining Example —
In the above example, each and every statement is preceeded with a comment to explain about the statement. Go through them to get clear understanding of example code.
MESSAGE ‘This is a Warning message’ TYPE ‘W’. — Displays ‘This is a Warning message’ on the output page status bar.
Example —
Display exit message.
Code —
*&---------------------------------------------------------------------*
*& Report Z_MESSAGE
*&---------------------------------------------------------------------*
*& Written by TutorialsCampus
*&---------------------------------------------------------------------*
REPORT Z_MESSAGE.
* Displaying Exit Message of type X
MESSAGE 'This is a Exit message' TYPE 'X'.
Output —
Explaining Example —
In the above example, each and every statement is preceeded with a comment to explain about the statement. Go through them to get clear understanding of example code.
MESSAGE ‘This is a Exit message’ TYPE ‘X’. — Displays ‘This is a Exit message’ on the output exit page.
Using the message class —
In this scenario, messages gets displayed from the message class that is defined by using MESSAGE-ID along with the REPORT command. Message number is a three-character code that can define a set of 1000 messages and those are accessed when MESSAGE command executed in the program.
Messages number ranges from 000 to 999 (i.e. 1000 messages). Each message associated with message number and the message length can be upto 80 characters.
When a message number used in the program, the corresponding message retrived from the message class and gets displayed.
Syntax —
MESSAGE {message-name} WITH field1 ... field4.
This addition replaces the placeholders «&1» to «&4» and «&» of the short text or «&V1&» to «&V4&» of the long text of of the operands field1, …, field4. Up to four operands field1 through field4 can be specified.
Messages are not always static and some part of the message can be filled with a dynamic or runtime text.
While creating a custom message, Amber sign (&) symbol used in the place of dynamic or runtime text.
The MESSAGE…WITH statement used to pass the dynamic or runtime text during the program execution.
Example —
Create a message class with a template message and pass the runtime text to complete the message.
First we need to create the message class with MESSAGE-ID by coding in the program.
Step-1: Code MESSAGE-ID along with REPORT shown like below. ZMG_CUSTMESG is the new message class.
Step-2: Double click on the message class name (ZMG_CUSTMESG) to create it. The Create Object diaglog gets opened.
Step-3: Click on «YES» to create new. It directs to Message Maintenance screen.
Step-4: Once the required information updated, move to «Messages» tab or Save button. Below screen gets appear.
Step-5: Select the desired package and click on «Local Object» button or «Save«. The Messages tab gets opened like below.
Step-6: Create the messages that required and click on «Save» button to save. Now newly created message class gets saved and it routes to ABAP Editor to continue the program coding.
Note! The message added with &. ‘&‘ used to pass custom information from the MESSAGE…WITH statement to the message text.
The text in the MESSAGE statement replaces ‘&‘ and displays the message.
Step-7: Open ABAP editor and complete the coding in the program.
The message defined for the message number 000 is ‘This is a & Message’. We are passing custom text(‘Informational’) in MESSAGE….WITH statement. So the ‘&’ replaces with ‘Informational’ and displays the message as ‘This is a Informational message’. As it is an message type ‘I’, it displays in separate dialog box.
Step-8: Execute the program to display the output.
Finally, the custom message displayed with dynamic or runtime text ‘Informational’. The output ‘This is Informational Message’ gets displayed on the seperate informational dialog box.
В ABAP реализован достаточно мощный механизм использования сообщений, в который интегрированы и локализация, и включение переменных в текст сообщений, передача этих сообщений в RFC, использование в классических и объектных исключениях, логирование, а также широкие возможности по выводу сообщений на различных вариантах GUI. При этом часто возникает необходимость передавать сообщения не поодиночке, а списком, например по завершении какого-то комплексного процесса, состоящего из шагов, либо при вызове программного модуля (RFC, BAPI и т.п.), возвращающего список сообщений.
Достаточно распространенной является практика использования таблицы со структурой BAPIRET в той или иной модификации. Как правило, таблица содержит не только сообщения, но и дополнительную информацию, как статусы, информация для логирования и другое.
Несмотря на простоту и распространенность этого решения, часто возникают похожие задачи по работе с данными из таких списков. Например получение наихудшего статуса, выбор сообщений с определенным статусом, добавление/удаление сообщений, логирование списка и прочее. Так или иначе на крупных проектах это приводит к необходимости создания некой обертки над списком сообщений, которая будет реализовывать весь функционал по работе с ним. Написание подобных классов — довольно увлекательный процесс, однако следует знать, что в стандарте уже существуют решения, способные покрыть почти все эти требования. О наиболее распространенных из них я расскажу в этой заметке.
##RECA
В стандартной поставке ABAP есть пакет RECA, включающий в себя множество утилитарных классов, решающих широкий спектр технических задач. Пакет входит в модуль RE-FX, который поставляется в составе SAP ERP, однако может быть найден и в других системах, например в EHS. Многие этих классов достойны отдельных статей, но сегодня мы поговорим об одном из них — CL_RECA_MESSAGE_LIST
, а точнее его интерфейсе IF_RECA_MESSAGE_LIST
, через который он и будет использоваться в программе.
Интерфейс имеет множество методов для работы со списком сообщений, для добавления сообщений из разных источников, для анализа сообщений и работы с логированием. Ниже я рассмотрю некоторые из них.
Инстанция создается через factory класс:
DATA:
lo_message_list TYPE REF TO if_reca_message_list.
lo_message_list = cf_reca_message_list=>create( ).
В метод можно передать параметры BAL объекта, если вы хотите сохранять в него сообщения. Также класс cf_reca_message_list
предоставляет инструментарий для поиска существующих BAL объектов.
IF_RECA_MESSAGE_LIST
позволяет добавлять сообщения из различных источников: через указание номера сообщения, из объекта исключения, из таблицы BAPIRET, из sy, а также из другого объекта сообщений.
lo_message_list->add(
id_msgty = 'S'
id_msgid = 'RDA'
id_msgno = 24
id_msgv1 = 'test'
).
*CALL BAPI
lo_message_list->add_from_bapi(
it_bapiret = lt_bapi_result
).
*CATCH cx_root INTO lo_exception.
lo_message_list->add_from_exception(
io_exception = lo_exception
).
lo_message_list->add_from_instance(
io_msglist = lo_message_list2
).
lo_message_list->add_symsg( ).
Стоит обратить внимание, что в интерфейсе нет метода, позволяющего добавлять сообщение из символьной переменной. Вероятно это связано с тем, что тексты в литералах являются плохим тоном в ABAP, так как не позволяют осуществлять перевод и затрудняют поддержку. Если вы один из тех, кто хардкодит тексты в строковые переменные, то при работе с этим объектом от такого подхода придется отказаться.
Этот контейнер удобно использовать как возвращаемый параметр метода, который выполняет цепочку действий, статус которых вы хотите в дальнейшем как-то использовать. Также удобно записывать сообщения, которые возвращают BAPI и другие ФМ, в частности те, что вызываются по RFC — зачастую они возвращают список сообщений именно в формате BAPIRET или близком к нему, который несложно сконвертировать в нужный.
DATA:
lt_message_1 TYPE bapiret1_tab,
lt_message_2 TYPE mmpur_message_list.
lo_message_list->add_from_bapi(
it_bapiret = CORRESPONDING #( lt_bapi_result )
).
lo_message_list->add_from_bapi(
it_bapiret = CORRESPONDING #( lt_message_2 MAPPING
type = msgty
id = msgid
number = msgno
message_v1 = msgv1
message_v2 = msgv2
message_v3 = msgv3
message_v4 = msgv4
)
).
Класс также позволяет получить сообщения обратно в удобном виде — получить все сообщения в виде таблицы BAPIRET, получить первое или последнее сообщение, отфильтровать сообщения по типу.
Помимо этого, класс позволяет получать различные аналитические данные по сообщениям, на основе которых удобно строить различные логигческие конструкции и проверки, не обращаясь раз за разом к самому списку напрямую. Например, можно получить статистику по всему списку сообщений, либо проверить, есть ли сообщения с определенным типом и есть ли сообщения вообще.
IF lo_message_list->has_messages_of_msgty( 'E' ).
* error processing of types E and X
ENDIF.
DATA(ls_msg_statistics) = lo_message_list->get_statistics( ).
IF ls_msg_statistics-msg_cnt_e > 0 OR ls_msg_statistics-msg_cnt_a > 0.
* error processing
ELSEIF ls_msg_statistics-msg_cnt_w > 0.
* warning processing
ELSE.
* success processing
ENDIF.
Ну и помимо прочего в контейнер встроен функционал по работе с BAL, например изменение заголовка, изменение уровня детализации сообщений и, конечно, сохранение. Пример использования:
lo_message_list = cf_reca_message_list=>create(
id_object = 'ZTEST'
id_subobject = 'SUBTEST'
id_extnumber = CONV #( sy-repid )
).
MESSAGE s000(00) INTO lv_dummy.
lo_message_list->add_symsg( ).
lo_message_list->store( ).
Для вывода сообщений класса на экран в классическом Dynpro можно воспользоваться ФМ RECA_GUI_MSGLIST_POPUP
, который выводит сообщения на стандартном экране лога.
Контейнер сообщений с подобным функционалом находит множество вариантов применения. Помимо очевидных вариантов вроде возвращаемого параметра, контейнер можно использовать, например, как атрибут класса исключения, куда можно записать несколько сообщений, описывающих возникшую ошибочную ситуацию, либо включить подробное описание шагов процесса, предшествующего ошибке. При обработке исключения эти сообщения можно включить в контейнер другого класса исключения, если обработка ошибки будет продолжена на более высоком уровне по стеку вызова, или при окончательной обработке ошибки вывести эти сообщения на экран или добавить в лог.
CLASS zcx_random_error DEFINITION
PUBLIC
INHERITING FROM cx_static_check
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_t100_dyn_msg .
INTERFACES if_t100_message .
METHODS constructor
IMPORTING
textid LIKE if_t100_message=>t100key OPTIONAL
previous LIKE previous OPTIONAL
msg_container TYPE REF TO if_reca_message_list OPTIONAL.
METHODS get_msg_container
RETURNING
VALUE(ro_msg_container) TYPE REF TO if_reca_message_list .
PRIVATE SECTION.
DATA go_msg_container TYPE REF TO if_reca_message_list .
ENDCLASS.
CLASS zcx_random_error IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor
EXPORTING
previous = previous.
CLEAR me->textid.
IF textid IS INITIAL.
if_t100_message~t100key = if_t100_message=>default_textid.
ELSE.
if_t100_message~t100key = textid.
ENDIF.
IF msg_container IS BOUND.
go_msg_container = msg_container.
ELSE.
go_msg_container = cf_reca_message_list=>create( ).
ENDIF.
ENDMETHOD.
METHOD get_msg_container.
ro_msg_container = go_msg_container.
ENDMETHOD.
ENDCLASS.
****************************************
TRY.
* some code
lo_message_list = cf_reca_message_list=>create( ).
* fill message container in between
RAISE EXCEPTION TYPE zcx_random_error
EXPORTING
msg_container = lo_message_list.
* some other code
CATCH zcx_random_error INTO DATA(lo_error).
* add error messages to log
lo_main_log->add_from_instance( lo_error->get_msg_container( ) ).
lo_main_log->store( abap_false ).
* show messages as popup
CALL FUNCTION 'RECA_GUI_MSGLIST_POPUP'
EXPORTING
io_msglist = lo_error->get_msg_container( ).
ENDTRY.
Также работая в рамках программы или функционального модуля можно создать глобальный класс логгера, используя этот контейнер, для упрощения частого обращения к объекту для записи логов. Также можно построить вокруг контейнера класс-обертку, который будет инициализироваться с контейнером в статическом атрибуте где-то в начале программы и служить той же цели — упростить логирование, минимизировав количество boilerplate кода.
Стоит учесть, что в классе не реализованы некоторые тонкости работы с BAL, так что он не будет 100% заменой. Однако он с легкостью покрывает 99% повседневных задач по работе с сообщениями. Несмотря на то, что этот контейнер имеет довольно топорный интерфейс взаимодействия и то, что в нем смешаны несколько ответственностей — хранение сообщений, их обработка и логирование, он покрывает большинство задач, связанных с передачей сообщений внутри системы и всевозможном взаимодействии с ними.
##OData
Широкое применение концепция контейнера сообщений получила в рамках OData Gateway. SAP в рамках OData API предоставляет контейнер /IWBEP/IF_MESSAGE_CONTAINER
, который используется для передачи сообщений через OData-канал клиенту OData-сервиса. Подробную информацию можно почитать в справке по компоненту SAP_GWFND, а я приведу краткий обзору функциональности интерфейса и варианты работы с ним.
Интерфейс имплементирует класс /iwbep/cl_mgw_msg_container
, в котором также есть статический factory-метод get_mgw_msg_container
, через который возможно создать новый контейнер.
DATA:
lo_msg_container TYPE REF TO /iwbep/if_message_container.
lo_msg_container = /iwbep/cl_mgw_msg_container=>get_mgw_msg_container( ).
Этот контейнер используется в различных классах OData Gateway, в частности в качестве атрибута в базовых классах исключений /iwbep/cx_mgw_busi_exception
и /iwbep/cx_mgw_tech_exception
. Эти классы используются для возврата информации об ошибках для их последующего отображения на клиентской стороне. Я не буду подробно останавливаться на этих классах, скажу лишь, что от них удобно наследовать свои классы исключений при работе в OData сервисе и передавать с ними все сообщения об ошибках.
Теперь немного подробнее про сам контейнер.
Как и предыдущий, этот интерфейс имеет несколько методов для добавления сообщений.
lo_msg_container->add_message(
iv_msg_type = 'S'
iv_msg_id = 'RDA'
iv_msg_number = 024
iv_msg_v1 = 'test'
).
*message list from bapi
lo_msg_container->add_messages_from_bapi(
it_bapi_messages = lt_bapi_result
).
*message list from BAL
lo_msg_container->add_messages_from_log(
it_log_messages = lt_bal_messages
).
*message from another container
lo_msg_container->add_messages_from_container( lo_msg_container2 ).
* exception in CATCH-block
lo_msg_container->add_message_from_exception( lo_error ).
Так как класс заточен на работу с OData, его методы содержат параметры, позволяющие задавать различные атрибуты ответа на запрос. Например, указывать, будет ли сообщение показываться в заголовке списка сообщений, или указывать название поля/компонента, спровоцировавшего ошибку.
Обратите внимание, что метод работает только для исключений, унаследованных от /iwbep/cx_mgw_base_exception
. Остальные исключения можно обработать следующим образом — после поимки исключения выбросить новое исключение, унаследованное от /iwbep/cx_mgw_base_exception
, передав текущее ему в качестве параметра, чтобы выше по стеку вызова уже работать с исключениями этого фреймворка. Сообщение из исходного исключения добавится в список ошибок при обработке исключения в самом фреймворке.
TRY.
RAISE EXCEPTION TYPE zcx_random_error.
CATCH cx_root INTO DATA(lo_some_error).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_tech_exception
EXPORTING
previous = lo_some_error.
ENDTRY.
Также в данном контейнере есть возможность добавлять сообщение из свободной текстовой переменной.
lo_msg_container->add_message_text_only(
iv_msg_type = 'E'
iv_msg_text = 'Some unexpected error!'
).
Возможно данный подход вполне оправдывает себя при отправке сообщений о технических ошибках через OData канал, но для логических (бизнес) ошибок всегда лучше использовать стандартные тексты, которые могут быть переведены на разные языки и легко найдены в коде при необходимости.
Как и предыдущий, этот контейнер обладает аналитическим функционалом.
IF lo_msg_container->get_worst_message_type( ) = 'E'.
* error processing
ELSEIF lo_msg_container->get_worst_message_type( ) = 'W'.
* not so bad
ELSE.
* perfect!
ENDIF.
Также есть возможность получать сообщения в виде таблицы типа /iwbep/t_message_container
.
Добавление сообщений при выбрасывании исключения может выглядеть следующим образом
lo_msg_container->add_message(
iv_msg_type = 'S'
iv_msg_id = 'RDA'
iv_msg_number = 123
).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = lo_msg_container
http_status_code = /iwbep/cx_mgw_busi_exception=>gcs_http_status_codes-not_found.
Контейнер не содержит функционала по работе с логом, но в данном случае это и не предполагается, для этого есть специализированные решения, вроде предыдущего контейнера.
#BOPF
Фреймворк бизнес-объектов имеет свой контейнер сообщений, адаптированный под работу с древовидной структурой модели бизнес-объектов и особенностей их функционала.
Основным контейнером сообщений является /BOBF/IF_FRW_MESSAGE
. Как и предыдущие рассмотренные примеры, контейнер создается через factory-метод соответствующего класса.
DATA:
lo_msg_container TYPE REF TO /bobf/if_frw_message.
lo_msg_container = /bobf/cl_frw_message_factory=>create_container( ).
Метод может возвращать объекты разных классов в зависимости от контекста Transaction Manager’а, но для пользователя контейнера эта разница скрыта за интерфейсом.
Контейнер имеет возможность добавлять стандартные сообщения и сообщения из других контейнеров или из классов исключений.
lo_msg_container->add( lo_msg_container2 ).
lo_msg_container->add_message(
is_msg = VALUE #(
msgty = 'S'
msgid = 'RDA'
msgno = 024
msgv1 = 'test'
)
).
lo_msg_container->add_exception( lo_error ).
При добавлении сообщения можно указать специфичные для BOPF параметры — место возникновения сообщения: ключ ноды БО, ключ конкретной инстанции этой ноды, атрибут этой ноды, который содержит ошибочные данные.
Однако основной функционал этого контейнера реализован в рамках другого подхода. В BOPF используются объектно-ориентированные сообщения. В самом контейнере есть два метода по добавлению объектно-ориентированных сообщений — простое добавление сообщения и добавления сообщения с явным указанием места возникновения сообщения (location). Намного интереснее поговорить про сами классы сообщений, но об этом чуть позже.
Как и остальные контейнеры, /BOBF/IF_FRW_MESSAGE
имеет методы для получения списка сообщений — возможно либо получить все сообщения таблицей, либо задать определенный фильтр.
DATA:
lt_message_list TYPE /bobf/cm_frw=>tt_frw,
lt_detailed_msg_list TYPE /bobf/t_frw_message_k.
*get all messages as object list
lo_msg_container->get(
IMPORTING
et_message = lt_message_list
).
*get error messages as detailed list
lo_msg_container->get_messages(
EXPORTING
iv_severity = /bobf/cm_frw=>co_severity_success
IMPORTING
et_message = lt_detailed_msg_list
).
Также есть возможность проверить наличие сообщений с ошибками. Дополнительно можно указать, включать ли в проверку сообщения из actions или determinations бизнес-объектов. По-умолчанию проверяются все.
IF lo_msg_container->check( ).
* error processing
ENDIF.
На этом основной функционал контейнера заканчивается. Куда интереснее подробнее рассмотреть концепцию сообщений, реализованную в BOPF.
###Объектно-ориентированные сообщения, используемые в BOPF.
Как уже было сказано выше, бизнес-объекты используют для обработки сообщений объекты, наследующиеся от абстрактного класса /BOBF/CM_FRW
. Технически он наследует класс CX_DYNAMIC_CHECK
, то есть представляет собой класс исключений. Технически. (Подробнее)
Смысл объектной обертки заключается в переходе от мета-сущности сообщений к объектам, которые удобно использовать в рамках программы (если, конечно, вы не из староверов, сидящих на процедурной парадигме). Такие сообщения довольно удобно создавать и использовать. Например, класс /BOBF/CM_FRW_SYMSG
, который имеет интерфейс для добавления сообщения в привычном виде.
DATA(lo_message) = NEW /bobf/cm_frw_symsg(
textid = VALUE #(
msgid = 'RDA'
msgno = 024
attr1 = 'test'
)
severity = 'E'
)
).
Их удобно добавлять в соответствующий контейнер.
lo_msg_container->add_cm( lo_message ).
lo_msg_container->add_cm(
NEW /bobf/cm_frw_symsg(
textid = VALUE #(
msgid = 'RDA'
msgno = 015
attr1 = 'one'
attr2 = 'two'
)
severity = 'S'
)
).
MESSAGE e024(rda) WITH 'example' INTO DATA(lv_dummy).
lo_msg_container->add_cm(
NEW /bobf/cm_frw_symsg(
textid = VALUE #(
msgid = sy-msgid
msgno = sy-msgno
attr1 = sy-msgv1
)
severity = sy-msgty
)
).
Можно добавлять текст сообщений из строковой переменной (хоть я и считаю это и не очень хорошей практикой).
lo_msg_container->add_cm(
NEW /bobf/cm_frw_symsg(
message_text = 'some custom text'
)
).
Также сообщения можно использовать как и обычные классы исключений, а при обработке на более высоком уровне добавить в контейнер. Особенно это удобно для того, чтобы обернуть сообщения от вызовов ФМ, используя соответствующий синтаксис 7.5 (не забудьте про интерфейс IF_T100_DYN_MSG
).
TRY.
* some coding
RAISE EXCEPTION TYPE zcm_hello
MESSAGE
ID sy-msgid
TYPE sy-msgty
NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
* more coding
RAISE EXCEPTION TYPE zcm_hello
EXPORTING
textid = zcm_hello=>some_error
severity = zcm_hello=>co_severity_error.
* some coding after all
CATCH /bobf/cm_frw INTO DATA(lo_message).
lo_msg_container->add_cm( lo_message ).
CATCH cx_root INTO DATA(lo_error).
MESSAGE lo_error TYPE 'X'.
ENDTRY.
Так как эти сообщения имплементируют интерфейс IF_MESSAGE
, их можно использовать для отображения на экране при помощи оператора MESSAGE (хотя, если вы работаете в рамках BOPF, скорее всего интерфейс реализован на WebDynpro или Fiori, нежели на SAPGUI).
При создании объекта сообщения можно указать дополнительные параметры — как уже известное нам место возникновения сообщения в BOPF, так и другие — SEVERITY — тип сообщения, SYMPTOM — описывает причину возникновения ошибки, LIFETIME — описывает категорию сообщения (временные или постоянные: первые просто возвращаются пользователю и забываются, вторые сохраняются вместе с моделью (релевангны только для временных (draft) БО и будут появляться на последующих шагах обработки, пока проблема не будет устранена).
lo_msg_container->add_cm(
NEW /bobf/cm_frw_symsg(
textid = ls_textid
severity = /bobf/cm_frw=>co_severity_warning
symptom = /bobf/if_frw_message_symptoms=>co_bo_inconsistency
lifetime = /bobf/cm_frw=>co_lifetime_transition
)
).
Несмотря на простоту и явность интерфейса объектных сообщений, он достаточно громоздок. Поэтому для упрощения рутинного кода в модулях, активно использующих BOPF, реализованы утилитарные классы для выполнения повторяющихся действий с контейнерами и сообщениями. Например в TM это /SCMTMS/CL_MSG_HELPER
, а в EHS это CL_EHFND_FW_APPL_LOG_HELPER
. Наверняка подобные есть и в других модулях, реализованных на бизнес-объектах — SLC, QIM, MOC и т.д. — найдите их самостоятельно. А если вы пришли на проект, где на бизнес-объектах реализована кастомерская логика с нуля (как на ISM-PrIMa в Deutsche Bahn), вы наверняка найдете с любовью написанный до вас Z-хелпер.
Для классов сообщений действует особый нейминг — *cm*, т.е. вы можете называть свои классы z*cm* или y*cm* (или /*/cm*, если вы работаете в вендорском пространстве имен). Семантически они ничем не отличаются от других классов исключений, и так же, как обычные классы исключений, могут иметь список сообщений, который можно редактировать через конструктор в se24 или вручную. Можно, например, добавить все сообщения какого-то модуля в один такой класс, а при создании сообщения передавать уже константу в textid — это сделает код более чистым, а сами сообщения можно будет найти через where-used list (работает только для глобальных классов).
CLASS zcm_hello DEFINITION
PUBLIC
INHERITING FROM /bobf/cm_frw
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_t100_dyn_msg .
CONSTANTS:
BEGIN OF some_error,
msgid TYPE symsgid VALUE 'RDA',
msgno TYPE symsgno VALUE '024',
attr1 TYPE scx_attrname VALUE '',
attr2 TYPE scx_attrname VALUE '',
attr3 TYPE scx_attrname VALUE '',
attr4 TYPE scx_attrname VALUE '',
END OF some_error .
METHODS constructor
IMPORTING
!textid LIKE if_t100_message=>t100key OPTIONAL
!previous LIKE previous OPTIONAL
!severity TYPE ty_message_severity OPTIONAL
!symptom TYPE ty_message_symptom OPTIONAL
!lifetime TYPE ty_message_lifetime DEFAULT co_lifetime_transition
!ms_origin_location TYPE /bobf/s_frw_location OPTIONAL
!mt_environment_location TYPE /bobf/t_frw_location OPTIONAL
!mv_act_key TYPE /bobf/act_key OPTIONAL
!mv_assoc_key TYPE /bobf/obm_assoc_key OPTIONAL
!mv_bopf_location TYPE /bobf/conf_key OPTIONAL
!mv_det_key TYPE /bobf/det_key OPTIONAL
!mv_query_key TYPE /bobf/obm_query_key OPTIONAL
!mv_val_key TYPE /bobf/val_key OPTIONAL .
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcm_hello IMPLEMENTATION.
METHOD constructor.
CALL METHOD super->constructor
EXPORTING
previous = previous
severity = severity
symptom = symptom
lifetime = lifetime
ms_origin_location = ms_origin_location
mt_environment_location = mt_environment_location
mv_act_key = mv_act_key
mv_assoc_key = mv_assoc_key
mv_bopf_location = mv_bopf_location
mv_det_key = mv_det_key
mv_query_key = mv_query_key
mv_val_key = mv_val_key.
CLEAR me->textid.
IF textid IS INITIAL.
if_t100_message~t100key = if_t100_message=>default_textid.
ELSE.
if_t100_message~t100key = textid.
ENDIF.
ENDMETHOD.
ENDCLASS.
Сгенерированный класс
Однако, несмотря на красоту описанного подхода, пока что он находит применение только внутри BOPF, в котором в принципе существует “своя атмосфера”. Поэтому для интеграции с другими частями SAP необходимо как-то преобразовать объектные сообщения в сообщения старой школы. Обычно такой функционал уже реализован в классах-хелперах модуля.
Несмотря на некоторые накладные расходы, сама концепция очень элегантна и позволяет работать с сообщениями в удобном формате, сочетающимся с современным стремлением ABAP стать нормальным языком программирования.
##Реализация в разных компонентах
Как мы все знаем, работники SAP никогда не общаются друг с другом, ходят в бар в разное время, а за обмен информацией между проектами можно положить учетку на стол и до конца жизни писать только в Z*. По крайней мере этим можно было бы объяснить такое огромное количество разнообразных реализаций одного и того же, как в различных продуктах этой компании. Каждый модуль, каждый фреймворк и технология зачастую имеют собственные реализации одних и тех же базовых либо более специфических вещей, которые не совместимы друг с другом.
Не обошла стороной эта тенденция и контейнеры сообщений. Свои контейнеры есть у различных модулей и фреймворков. Вот несколько тех, которые я встречал в работе:
CL_LOG_PPF
— контейнер PPFCL_EHFND_FW_LOGGER
— контейнер ENA (объектная обертка над BOPF) в EHS
Есть и другие, вы можете встретить их при работе с разными частями SAP. Но суть будет везде примерно одинакова, разве что адаптирована под контекст выполняемых задач.
##Что же выбрать?
В итоге мы имеем дюжину контейнеров сообщений с различным функционалом. Какой же лучше? Какой использовать в повседневной разработке?
Скорее всего, на этот вопрос нельзя дать однозначного ответа. Каждый хорош по-своему, поэтому используйте тот, который близок к контексту вашей разработки. Если вы разрабатываете OData-сервис, логично будет построить обмен сообщениями в рамках контейнера /IWBEP/IF_MESSAGE_CONTAINER
и классов исключений, используемых в фреймворке. Аналогично и для других фреймворков или модулей — BOPF, PPF и т.д. В других случаях я советую использовать IF_RECA_MESSAGE_LIST
, как наиболее универсальный. Если же в вашем модуле его нет (например в EWM — нет), поищите какую-то местную реализацию, скорее всего она там есть, если модуль моложе пятнадцати лет. Если и такого нет, воспользуйтесь каким-нибудь готовым Z-решением, благо их есть несколько довольно хороших. В любом случае такая обертка будет гораздо удобнее в работе, чем таскание туда-сюда таблиц вроде BAPIRET.
Стремитесь к чистому объектно-ориентированному коду с минимумом неявных операций, коими являются многие операции с сообщениями, вроде классических исключений. Контейнеры сообщений помогут решить эту задачу элегантным и удобным способом, а также помогут использовать информацию из списка сообщений легким для разработчика путем.