- Misc ABAP Classes
- Excursion: Available Classes in ABAP for Cloud Development
- Creating and Transforming UUIDs
- Displaying Output in the ADT Console
- RAP
- Transactional Consistency
- Numbers and Calculations
- String Processing
- Time and Date
- Runtime Type Services (RTTS)
- Assignments
- Information about Non-Initial Structure Components
- Comparing Content of Compatible Internal Tables
- Dynamic Programming
- Context Information
- XML/JSON
- ABAP Repository Object Information
- Generating ABAP Repository Objects
- Call Stack
- Sending Emails
- Tenant Information
- Exception Classes
- Parallel Processing
- Application Log
- Running Code in the Background
- Locking
- Calling Services
- Reading and Writing XLSX Content
- Zip Files
- ABAP Unit
This ABAP cheat sheet contains a selection of released ABAP classes that are available in ABAP for Cloud Development. It serves as a quick introduction, along with code snippets to explore the functionality in action.
💡 Note
- The cheat sheet is not a comprehensive overview, and the code snippets do not claim to be comprehensive as far as options, methods, or parameters are concerned. It is intended to give you a rough overview, for you to get an idea. It is an invitation to a more in-depth exploration.
- For more information and where available, refer to the class documentation (for example, choose F2 when the cursor is on the class name in ADT), the ABAP Keyword Documentation, and the SAP Help Portal documentation.
- Disclaimer
If available to you, you have accessed an SAP BTP ABAP Environment using the ABAP development tools for Eclipse (ADT). Access to SAP-provided repository objects is restricted to objects that have been released for ABAP for Cloud Development (released APIs). You can find the released repository objects in the Project Explorer view in ADT under Released Objects. The classes are located in the Source Code Library folder:
You can also programmatically get the released obects. You can use specific XCO classes or a CDS view, as shown in the example code snippet below.
SELECT ReleasedObjectType, ReleasedObjectName, ReleaseState
FROM i_apisforclouddevelopment
WHERE releasestate = 'RELEASED'
AND ReleasedObjectType = 'CLAS'
ORDER BY ReleasedObjectName
INTO TABLE @DATA(released_classes).
Class | Details/Code Snippet |
CL_SYSTEM_UUID |
Creating and and converting system UUIDs with various algorithms
"Creating UUIDs in binary format (16 bytes)
TRY.
DATA(uuid) = cl_system_uuid=>create_uuid_x16_static( ) .
CATCH cx_uuid_error.
ENDTRY.
"e.g. B2B012691AC31EDEADA0A495A7130961 |
XCO_CP_UUID |
Transforming between different UUID formats
DATA(uuid_c36) = xco_cp_uuid=>format->c36->to_uuid( '7cd44fff-036a-4155-b0d2-f5a4dfbcee92' ).
"7CD44FFF036A4155B0D2F5A4DFBCEE92
DATA(uuid_c36_to_c32) = CONV sysuuid_c32( xco_cp_uuid=>format->c32->from_uuid( uuid_c36 ) ).
"7cd44fff-036a-4155-b0d2-f5a4dfbcee92
DATA(uuid_c32_to_c36) = to_lower( CONV sysuuid_c36( xco_cp_uuid=>format->c36->from_uuid( uuid_c36 ) ) ). |
Class | Details/Code Snippet |
CL_DEMO_CLASSRUN |
As an alternative to using the IF_OO_ADT_CLASSRUN interface for displaying output in the console, you can also use the CL_DEMO_CLASSRUN class, which offers more methods.
For more information, refer to this blog.
The following example makes use of the CL_DEMO_CLASSRUN class. A structure and an internal table are displayed in the console. A structure component is a reference variable, which is automatically dereferenced. Plus, the write_xml method is shown, which displays XML data.
CLASS zcl_some_class DEFINITION
INHERITING FROM cl_demo_classrun
PUBLIC
CREATE PUBLIC.
PUBLIC SECTION.
METHODS main REDEFINITION.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD main.
TYPES: BEGIN OF s,
comp1 TYPE string,
comp2 TYPE i,
comp3 TYPE string_table,
comp4 TYPE REF TO string,
END OF s,
it_type TYPE TABLE OF s WITH EMPTY KEY.
DATA(struct) = VALUE s( comp1 = `Hello`
comp2 = 1
comp3 = VALUE #( ( `a` ) ( `b` ) ( `a` ) ( `p` ) )
comp4 = NEW #( `world` ) ).
DATA(itab) = VALUE it_type( ( struct )
( comp1 = `Hi`
comp2 = 2
comp3 = VALUE #( ( `x` ) ( `y` ) ( `z` ) )
comp4 = NEW #( `ABAP` ) ) ).
out->write( struct ).
out->write( itab ).
DATA(some_xml) = cl_abap_conv_codepage=>create_out( )->convert(
`<hi><word1>hallo</word1><word2>how</word2><word3>are</word3><word4>you</word4></hi>` ).
out->write( some_xml ).
out->write_xml( some_xml ).
ENDMETHOD.
ENDCLASS. |
Class | Details/Code Snippet |
CL_ABAP_BEHV_AUX |
A utility class for retrieving information about RAP handler implementations, such as the current context of RAP handler/saver methods, the handler kind, and the current RAP transactional phase (e.g., RAP interaction phase.
"Getting the current context of RAP handler implementations;
"storing the information (true/false) in a variable declared inline
cl_abap_behv_aux=>get_current_context( IMPORTING from_projection = FINAL(fr_proj)
from_interface = FINAL(fr_int)
in_local_mode = FINAL(loc_mode)
draft_activate = FINAL(dr_act)
for_permissions = FINAL(for_perm)
privileged = FINAL(priv) ).
"Getting the root entity name and handler kind
"For the latter, you can check the fixed values of abp_behv_kind (e.g., 'R' stands for read)
DATA ent TYPE abp_root_entity_name.
FINAL(handler_kind) = cl_abap_behv_aux=>get_current_handler_kind( IMPORTING root_entity = ent ).
"Getting information about the current transactional phase
FINAL(phase) = cl_abap_behv_aux=>get_current_phase( ).
"e.g. INTERACTION or EARLY_SAVE |
CL_ABAP_BEHAVIOR_HANDLER |
Used for RAP handler classes that inherit from class CL_ABAP_BEHAVIOR_HANDLER .
"Skeleton of a RAP handler class declaration part in a CCIMP include
CLASS lcl_handler DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
... "Here go RAP handler method declarations
ENDCLASS.
... |
CL_ABAP_BEHAVIOR_SAVER |
Used as base class from which a RAP saver class in an ABAP behavior pool (ABP) inherits. The RAP saver class must be defined in the CCIMP include of an ABP.
"Skeleton of a RAP saver class declaration part in a CCIMP include
CLASS lsc_bdef DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS finalize REDEFINITION.
METHODS check_before_save REDEFINITION.
METHODS save REDEFINITION.
METHODS cleanup REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.
... |
CL_ABAP_BEHAVIOR_SAVER_FAILED |
"Skeleton of a RAP saver class declaration part in a CCIMP include
CLASS lsc_bdef DEFINITION INHERITING FROM cl_abap_behavior_saver_failed.
PROTECTED SECTION.
...
METHODS save REDEFINITION.
"Unlike in CL_ABAP_BEHAVIOR_SAVER, the RAP response parameters failed and reported are included.
...
ENDCLASS.
... |
CL_ABAP_BEHAVIOR_EVENT_HANDLER |
It is used as base class from which a RAP event handler class in its CCIMP include inherits. Its purpose is to locally consume RAP business events.
More information: ABAP for RAP Business Events.
"Skeleton of a RAP event handler class declaration part in a CCIMP include
"The assumption is that there are the events 'created', 'updated', and
"'deleted' specified in the BDEF.
CLASS lhe_event DEFINITION INHERITING FROM cl_abap_behavior_event_handler.
PRIVATE SECTION.
METHODS on_updated FOR ENTITY EVENT
updated FOR some_bdef~updated.
METHODS on_deleted FOR ENTITY EVENT
deleted FOR some_bdef~deleted.
METHODS on_created FOR ENTITY EVENT
created FOR some_bdef~created.
ENDCLASS.
... |
Class | Details/Code Snippet |
CL_ABAP_TX |
...
"Activating the modify transactional phase
cl_abap_tx=>modify( ).
"The following database modification statement is not allowed in the
"modify transactional phase. In certain contexts, e.g. in ABAP Cloud,
"the runtime error BEHAVIOR_ILLEGAL_STMT_IN_CALL occurs.
MODIFY zdemo_abap_carr FROM TABLE @( VALUE #(
( carrid = 'XY'
carrname = 'XY Airlines'
currcode = 'EUR'
url = 'some_url' ) ) ).
...
"Activating the save transactional phase
cl_abap_tx=>save( ).
"In this phase, database modifications are allowed.
MODIFY zdemo_abap_carr FROM TABLE @( VALUE #(
( carrid = 'XY'
carrname = 'XY Airlines'
currcode = 'EUR'
url = 'some_url' ) ) ).
... |
Class | Details/Code Snippet |
CL_ABAP_MATH |
For operations with (decimal) floating point numbers and for providing constants for minimum and maximum values.
"Constants for the minimum and maximum values of built-in numeric types
"Example: Type i
DATA(min_int4) = cl_abap_math=>min_int4. "-2147483648
DATA(max_int4) = cl_abap_math=>max_int4. "2147483647
"Rounding binary floating point number to 15 places using commercial rounding
DATA flpnum TYPE f VALUE '1.005'.
DATA(rd) = cl_abap_math=>round_f_to_15_decs( flpnum ). "1.005000000000001E0
DATA(str2dcm) = |{ flpnum DECIMALS = 2 }|. "1.00
DATA(str2dcm_rd) = |{ cl_abap_math=>round_f_to_15_decs( flpnum ) DECIMALS = 2 }|. "1.01
"Properties of decimal floating point numbers
"Example: 98.765; an integer with fixed precision, i.e. a given length (the length of 98765),
"which is scaled by dividing through a power of 10 (10 powered by n, representing
"the number of decimal places; in the example, the scaling is the negative exponent)
DATA(decf) = CONV decfloat34( '98.765' ).
DATA(scale) = cl_abap_math=>get_scale( decf ). "3
DATA(precision) = cl_abap_math=>get_number_of_digits( decf ). "5 |
CL_ABAP_DECFLOAT |
For handling decimal floating point numbers.
"Converting currency amounts to decimal floating point numbers using a
"a currency key. The reverse is also possible.
DATA(dec) = CONV decfloat34( '12340'
"'123.456'
).
DATA pdec TYPE p LENGTH 9 DECIMALS 2.
cl_abap_decfloat=>convert_decfloat_to_curr( EXPORTING amount_decfloat = dec
cuky = 'EUR'
IMPORTING amount_curr = pdec ) .
"12340.0
"123.46
"Converting strings to decimal floating point numbers
"The character string is converted to a value of type decfloat34,
"which is passed back in VALUE.
DATA dcfl34 TYPE decfloat34.
DATA return_code TYPE i.
DATA str TYPE string VALUE `1234.8652`.
TRY.
cl_abap_decfloat=>read_decfloat34( EXPORTING string = str
IMPORTING value = dcfl34
rc = return_code ).
CATCH cx_sy_conversion_overflow cx_abap_decfloat_invalid_char cx_abap_decfloat_parse_err.
ENDTRY. |
CL_ABAP_BIGINT |
For calculations with integers of any size (e.g. to avoid the risk of an arithmetic overflow). Find more information in
this blog, and check out the different methods available.
"Creating an arbitrary precision integer from a variable of type i
"and calculating the power; converting the result to string
DATA(pow1) = cl_abap_bigint=>factory_from_int4( 10 )->pow( 10 )->to_string( ).
"Comparison with integer value (the maximum value of type i; see the class above)
DATA(compare_i) = cl_abap_bigint=>factory_from_int4( 10 )->pow( 10 )->compare_int4( cl_abap_math=>max_int4 ). "LARGER
"10000000000 (result)
"2147483647 (maximum value for type i)
"Comparison with the ipow function (here, an exception is raised)
TRY.
DATA(pow2) = ipow( base = 10 exp = 10 ).
CATCH cx_sy_arithmetic_overflow.
ENDTRY. |
CL_ABAP_RATIONAL |
For calculations with rational numbers without precision loss and rounding errors.
"Creating a rational number from a string
DATA(rat_num) = cl_abap_rational=>factory_from_string(
EXPORTING iv_value = `-1/3` ).
"Performing an addition and converting the result to string
DATA(addition_res) = rat_num->add( cl_abap_rational=>factory_from_string(
EXPORTING iv_value = `3/2` ) )->to_string( ). "7/6 |
CL_ABAP_RANDOM* |
For generating arbitrary numbers for different numeric types:
CL_ABAP_RANDOM_INT (type i ),
CL_ABAP_RANDOM_INT8 (int8 ),
CL_ABAP_RANDOM_FLOAT (f ),
CL_ABAP_RANDOM_PACKED (p ),
CL_ABAP_RANDOM_PACKED_DEC1 - CL_ABAP_RANDOM_PACKED_DEC14 (p with 1 to 14 decimal places),
CL_ABAP_RANDOM_DECFLOAT16 (decfloat16 ),
CL_ABAP_RANDOM_DECFLOAT34 (decfloat34 )
"Getting multiple random integers that are to be stored in an
"internal table of type i
TYPES int_tab_type TYPE TABLE OF i WITH EMPTY KEY.
DATA int_tab TYPE int_tab_type.
"The optional parameters are explicitly specified in the example;
"'seed' represents the initial starting number, you can use
"'cl_abap_random=>seed( )' to specify an arbitrary start value
DATA(random_num1) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = 100 ).
DO 3 TIMES.
APPEND random_num1->get_next( ) TO int_tab.
ENDDO.
"Getting a random integer in one go using method chaining
DATA(random_num2) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 100
max = 1000 )->get_next( ). |
Class | Details/Code Snippet |
CL_ABAP_GZIP* |
For (de)compressing character strings and byte strings using GZIP:
CL_ABAP_GZIP ,
CL_ABAP_GZIP_BINARY_STREAM ,
CL_ABAP_GZIP_TEXT_STREAM ,
CL_ABAP_UNGZIP_BINARY_STREAM ,
CL_ABAP_UNGZIP_TEXT_STREAM
"------- (De)compressing binary data -------
DATA(str) = `This is a data object of type string. It should be converted to xstring, compressed and decompressed.`.
DATA(xstr) = cl_abap_conv_codepage=>create_out( )->convert( str ).
DATA xstr_comp TYPE xstring.
"Compressing binary data
TRY.
cl_abap_gzip=>compress_binary( EXPORTING raw_in = xstr
IMPORTING gzip_out = xstr_comp ).
CATCH cx_parameter_invalid_range cx_sy_buffer_overflow cx_sy_compression_error.
ENDTRY.
"Comparing the length of the data objects
DATA(len_xstr) = xstrlen( xstr ). "101
DATA(len_xstr_comp) = xstrlen( xstr_comp ). "81
"Decompressing binary data
DATA xstr_decomp TYPE xstring.
TRY.
cl_abap_gzip=>decompress_binary( EXPORTING gzip_in = xstr_comp
IMPORTING raw_out = xstr_decomp ).
CATCH cx_parameter_invalid_range cx_sy_buffer_overflow cx_sy_compression_error.
ENDTRY.
DATA(len_xstr_decomp) = xstrlen( xstr_decomp ). "101
DATA(conv_str) = cl_abap_conv_codepage=>create_in( )->convert( xstr_decomp ).
"abap_true
DATA(is_equal) = xsdbool( len_xstr = len_xstr_decomp AND str = conv_str ).
"------- (De)compressing character strings -------
DATA zipped TYPE xstring.
TRY.
cl_abap_gzip=>compress_text( EXPORTING text_in = `Hello world`
IMPORTING gzip_out = zipped ).
CATCH cx_parameter_invalid_range cx_sy_buffer_overflow cx_sy_conversion_codepage cx_sy_compression_error.
ENDTRY.
DATA txt TYPE string.
TRY.
cl_abap_gzip=>decompress_text( EXPORTING gzip_in = zipped
IMPORTING text_out = txt ).
CATCH cx_parameter_invalid_range cx_sy_buffer_overflow cx_sy_conversion_codepage cx_sy_compression_error.
ENDTRY.
ASSERT txt = `Hello world`. |
CL_ABAP_CHAR_UTILITIES |
Provides utilities for string processing, such as attributes that represent new lines and horizontal tabs.
DATA(tabbed) = `#` && cl_abap_char_utilities=>horizontal_tab && `#`.
"The following attributes can be replaced by a representation of
"the control characters in a string template.
ASSERT cl_abap_char_utilities=>newline = |\n|.
ASSERT cl_abap_char_utilities=>horizontal_tab = |\t|.
ASSERT cl_abap_char_utilities=>cr_lf = |\r\n|. |
CL_ABAP_STRING_UTILITIES |
For processing text strings, such as handling trailing blanks in character strings (i.e. data objects of type string ).
DATA(string) = `ABAP `.
"Removing trailing blanks
cl_abap_string_utilities=>del_trailing_blanks( CHANGING str = string ).
"`ABAP`
"Preserving trailing blanks when assigning text fields to data objects of
"type string
DATA(chars) = 'ABAP '.
cl_abap_string_utilities=>c2str_preserving_blanks( EXPORTING source = chars
IMPORTING dest = DATA(str_w_blanks) ).
"`ABAP `
DATA(str_no_blanks) = CONV string( chars ).
"`ABAP` |
CL_ABAP_CONV_CODEPAGE |
For handling code pages, converting strings to the binary representation of different code pages and vice versa.
DATA(hi) = `Hello world`.
"string -> xstring
"Note: UTF-8 is used by default. Here, it is specified explicitly.
TRY.
DATA(conv_xstring) = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( hi ).
CATCH cx_sy_conversion_codepage.
ENDTRY.
"48656C6C6F20776F726C64
"xstring -> string
DATA(conv_string) = cl_abap_conv_codepage=>create_in( )->convert( conv_xstring ).
"Hello world |
CL_ABAP_REGEX CL_ABAP_MATCHER |
DATA(str) = `a1 # B2 ? cd . E3`.
"Creating a regex instance for PCRE regular expressions
"In the example, regex_inst has the type ref to cl_abap_regex.
DATA(regex_inst) = cl_abap_regex=>create_pcre( pattern = `\D\d` "Any-non digit followed by a digit
ignore_case = abap_true ).
"Creating an instance of CL_ABAP_MATCHER using the method CREATE_MATCHER of the class CL_ABAP_REGEX
"You can also specify internal tables with the 'table' parameter and more.
DATA(matcher) = regex_inst->create_matcher( text = str ).
"Finding all results using the 'find_all' method
"In the example, result has the type match_result_tab containing the findings.
DATA(result) = matcher->find_all( ).
"Using method chaining
DATA(res) = cl_abap_regex=>create_pcre( pattern = `\s\w` "Any blank followed by any word character
ignore_case = abap_true )->create_matcher( text = str )->find_all( ). |
XCO_CP |
Offers various options to process strings using the XCO Library; see a selection in the code snippet
"--------- Extracting a substring from a string ---------
DATA(some_string) = `abcdefghijklmnopqrstuvwxyz`.
"Creating an encapsulation of a string using XCO
DATA(str) = xco_cp=>string( some_string ).
"Using the FROM and TO methods, you can determine
"the character position. Note that the value includes the
"character at the position specified.
"The character index pattern for the example string above
"is (the string has 26 characters in total):
"a = 1, b = 2, c = 3 ... z = 26
"a = -26, b = -25, c = -24 ... z = -1
"Providing a value that is out of bounds means that
"the first (or the last) character of the string is used
"by default.
"Note: When combining FROM and TO, e.g. with method
"chaining ...->from( ...)->to( ... ), note that another
"instance is created with the first 'from', and another
"character index pattern is created based on the new
"and adjusted string value.
"bcdefghijklmnopqrstuvwxyz
DATA(sub1) = str->from( 2 )->value.
"defghijklmnopqrstuvwxyz
DATA(sub2) = str->from( -23 )->value.
"vwxyz
DATA(sub3) = str->from( -5 )->value.
"abcde
DATA(sub4) = str->to( 5 )->value.
"ab
DATA(sub5) = str->to( -25 )->value.
"Result of 1st 'from' method call: bcdefghijklmnopqrstuvwxyz
"Based on this result, the 'to' method call is
"applied.
"bcdefg
DATA(sub6) = str->from( 2 )->to( 6 )->value.
"Result of 1st 'to' method call: abcdefghijklmnopq
"Based on this result, the 'from' method call is
"applied.
"defghijklmnopq
DATA(sub7) = str->to( -10 )->from( 4 )->value.
"Values that are out of bounds.
"In the example, the first and last character of the
"string are used.
"abcdefghijklmnopqrstuvwxyz
DATA(sub8) = str->from( 0 )->to( 100 )->value.
"--------- Splitting and joining ---------
"Splitting a string into a string table
DATA(str_table) = xco_cp=>string( `Hello.World.ABAP` )->split( `.` )->value.
"Hello
"World
"ABAP
"Concatenating a string table into a string; specifying a delimiter
str_table = VALUE #( ( `a` ) ( `b` ) ( `c` ) ).
"a, b, c
DATA(conc_str1) = xco_cp=>strings( str_table )->join( `, ` )->value.
"Concatenating a string table into a string; specifying a delimiter and
"reversing the table order
"c / b / a
DATA(conc_str2) = xco_cp=>strings( str_table )->reverse( )->join( ` / ` )->value.
"--------- Prepending and appending strings ---------
DATA(name) = xco_cp=>string( `Max Mustermann` ).
"Max Mustermann, Some Street 1, 12345 Someplace
DATA(address) = name->append( `, Some Street 1, 12345 Someplace` )->value.
"Mr. Max Mustermann
DATA(title) = name->prepend( `Mr. ` )->value.
"--------- Transforming to lowercase and uppercase ---------
"ABAP
DATA(to_upper) = xco_cp=>string( `abap` )->to_upper_case( )->value.
"hallo world
DATA(to_lower) = xco_cp=>string( `HALLO WORLD` )->to_lower_case( )->value.
"--------- Checking if a string starts/ends with a specific string ---------
DATA check TYPE string.
DATA(str_check) = xco_cp=>string( `Max Mustermann` ).
"yes
IF str_check->ends_with( `mann` ).
check = `yes`.
ELSE.
check = `no`.
ENDIF.
"no
IF str_check->starts_with( `John` ).
check = `yes`.
ELSE.
check = `no`.
ENDIF.
"--------- Converting strings to xstrings using a codepage ---------
"536F6D6520737472696E67
DATA(xstr) = xco_cp=>string( `Some string` )->as_xstring( xco_cp_character=>code_page->utf_8 )->value.
"--------- Camel case compositions and decompositions with split and join operations ---------
"Pascal case is also possible
"someValue
DATA(comp) = xco_cp=>string( `some_value` )->split( `_` )->compose( xco_cp_string=>composition->camel_case )->value.
"Camel case decomposition
"some_value
DATA(decomp) = xco_cp=>string( `someValue` )->decompose( xco_cp_string=>decomposition->camel_case )->join( `_` )->value.
"------ Processing Base64 representations of raw binary data ------
DATA(a_string) = `Hello world`.
"string -> xstring
"Result: 48656C6C6F20776F726C64
DATA(conv_xstring) = xco_cp=>string( a_string
)->as_xstring( xco_cp_character=>code_page->utf_8
)->value.
"Encoding of raw binary data into its Base64 representation
"Result: SGVsbG8gd29ybGQ=
DATA(raw2base64) = xco_cp=>xstring( conv_xstring
)->as_string( xco_cp_binary=>text_encoding->base64
)->value.
"Decoding of a Base64 representation into raw binary data
"Result: 48656C6C6F20776F726C64
DATA(base642raw) = xco_cp=>string( raw2base64
)->as_xstring( xco_cp_binary=>text_encoding->base64
)->value.
"xstring -> string
"Result: Hello world
DATA(conv_string_xco) = xco_cp=>xstring( base642raw
)->as_string( xco_cp_character=>code_page->utf_8
)->value.
"--------- Matching string against regular expression ---------
DATA match TYPE string.
"yes
IF xco_cp=>string( ` 1` )->matches( `\s\d` ).
match = 'yes'.
ELSE.
match = 'no'.
ENDIF.
"no
IF xco_cp=>string( ` X` )->matches( `\s\d` ).
match = 'yes'.
ELSE.
match = 'no'.
ENDIF. |
💡 Note
In ABAP for Cloud Development, do not use the date and time-related system fields such assy-datum
andsy-uzeit
, and others. User-related time and date values can be retrieved using the XCO library. For code snippets, see the Date, Time, and Time Stamp cheat sheet.
Class | Details/Code Snippet |
CL_ABAP_UTCLONG |
For handling time stamps in time stamp fields (data objects with type utclong ).
"utclong_current: Using the built-in function to create a UTC time stamp
DATA(low_timestamp) = utclong_current( ).
"utclong_add: Using the built-in function to create a UTC time stamp and
"adding time values
DATA(high_timestamp) = utclong_add( val = low_timestamp
days = 1
hours = 2
minutes = 3
seconds = 4 ).
"diff: Calculating time differences
"In the example, the returned values correspond to the ones added above.
cl_abap_utclong=>diff( EXPORTING high = high_timestamp
low = low_timestamp
IMPORTING days = DATA(days)
hours = DATA(hours)
minutes = DATA(minutes)
seconds = DATA(seconds) ).
"read: Reading a time stamp from a string
DATA(ts) = |{ utclong_current( ) TIMESTAMP = ENVIRONMENT TIMEZONE = 'UTC' }|.
TRY.
cl_abap_utclong=>read( EXPORTING string = ts
timezone = 'UTC'
IMPORTING value = DATA(utc_ts) ).
CATCH cx_abap_utclong_invalid.
ENDTRY.
"e.g. 2024-01-01T13:01:54.546134Z |
CL_ABAP_TSTMP |
For calculating and converting time stamps in packed numbers (types timestamp and timestampl )
"Creating a time stamp of type timestamp (the inline creation creates
"a data object with that type by default)
GET TIME STAMP FIELD DATA(ts1).
"e.g. 20240101131220
"Calculations for time stamps in packed numbers
"Adding 1 hour
DATA(ts2) = cl_abap_tstmp=>add( tstmp = ts1
secs = 3600 ).
"e.g. 20240101141220.0000000
"Subtracting 2 hours
DATA(ts3) = cl_abap_tstmp=>subtractsecs( tstmp = ts1
secs = 7200 ).
"e.g. 20240101111220.0000000
"Type timestampl
DATA tsl1 TYPE timestampl.
GET TIME STAMP FIELD tsl1.
"e.g. 20240101131701.3309040
"Converting type timestampl to timestamp
DATA(ts4) = cl_abap_tstmp=>move_to_short( tsl1 ).
"e.g. 20240101131701
"Converting types timestamp/timestampl to UTCLONG
DATA(ts2utcl) = cl_abap_tstmp=>tstmp2utclong( tsl1 ).
"e.g. 2024-01-01 13:19:23.8622560
"Converting type utclong to timestamp
DATA(utcl2ts) = cl_abap_tstmp=>utclong2tstmp_short( ts2utcl ).
"e.g. 20240101132231
"Converting type utclong to timestampl
DATA(utcl2tsl) = cl_abap_tstmp=>utclong2tstmp( ts2utcl ).
"e.g. 20240101132231.0667200 |
XCO_CP_TIME |
Class of the XCO time library that provides abstractions for getting and working with date and time information. Find more details here.
"Creating a time stamp
"As a result (which is also true for other results below),
"you get a handler with which you can get further information
"(check the options following '->').
DATA(m_moment) = xco_cp_time=>moment(
iv_year = '2024'
iv_month = '01'
iv_day = '01'
iv_hour = '12'
iv_minute = '34'
iv_second = '55' ).
"Getting the created time stamp as a string
"20240101123455
DATA(m2_moment_string) = m_moment->as( xco_cp_time=>format->abap )->value.
"... and with other formats applied.
"20240101T123455
DATA(m3_moment_format_a) = m_moment->as( xco_cp_time=>format->iso_8601_basic )->value.
"2024-01-01T12:34:55
DATA(m4_moment_format_b) = m_moment->as( xco_cp_time=>format->iso_8601_extended )->value.
"Getting user time zone
"e.g. UTC
DATA(m1_user_time_zone) = xco_cp_time=>time_zone->user->value.
"Getting the current moment in the time zone of the current user
"e.g. 2024-01-01T08:54:39
DATA(m5_cur_moment4user) = xco_cp=>sy->moment( xco_cp_time=>time_zone->user )->as( xco_cp_time=>format->iso_8601_extended )->value.
"Current moment in UTC
"e.g. 2024-01-01T08:54:39 (result is the same as above in the case of the cheat sheet example)
DATA(m6_cur_moment_utc) = xco_cp=>sy->moment( xco_cp_time=>time_zone->utc )->as( xco_cp_time=>format->iso_8601_extended )->value.
"Current UNIX timestamp
"e.g. 1703863291
DATA(m7_unix_tstmp) = xco_cp=>sy->unix_timestamp( )->value.
"For the time stamp, you can also use the TIME method
"e.g. 10:27:59
DATA(m8_time) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->as( xco_cp_time=>format->iso_8601_extended )->value.
"Getting second, minute, hour information
"e.g. 59
DATA(m9_seconds) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->second.
"e.g. 27
DATA(m10_minutes) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->minute.
"e.g. 10
DATA(m11_hours) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->hour.
"Calculations with time
"Adding
"e.g. 11:29:00
DATA(m12_add_time) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->add( iv_hour = 1 iv_minute = 1 iv_second = 1 )->as( xco_cp_time=>format->iso_8601_extended )->value.
"Subtracting
"e.g. 09:26:58
DATA(m13_subtract_time) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->subtract( iv_hour = 1 iv_minute = 1 iv_second = 1 )->as( xco_cp_time=>format->iso_8601_extended )->value.
"Getting date information
"e.g. 2024-01-01
DATA(m14_date) = xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value.
"e.g. 01
DATA(m15_day) = xco_cp=>sy->date( )->day.
"e.g. 01
DATA(m16_month) = xco_cp=>sy->date( )->month.
"e.g. 2024
DATA(m17_year) = xco_cp=>sy->date( )->year.
"Calculations with dates
"Adding
"e.g. 2025-02-02
DATA(m18_add_date) = xco_cp=>sy->date( )->add( iv_day = 1 iv_month = 1 iv_year = 1 )->as( xco_cp_time=>format->iso_8601_extended )->value.
"Subtracting
"e.g. 2022-12-31
DATA(m19_subtract_date) = xco_cp=>sy->date( )->subtract( iv_day = 1 iv_month = 1 iv_year = 1 )->as( xco_cp_time=>format->iso_8601_extended )->value. |
Class | Details/Code Snippet |
CL_ABAP_TYPEDESCR |
RTTS represent a hierarchy of type description classes containing methods for:
Apart from CL_ABAP_TYPEDESCR | |--CL_ABAP_DATADESCR | | | |--CL_ABAP_ELEMDESCR | | | | | |--CL_ABAP_ENUMDESCR | | | |--CL_ABAP_REFDESCR | |--CL_ABAP_COMPLEXDESCR | | | |--CL_ABAP_STRUCTDESCR | |--CL_ABAP_TABLEDESCR | |--CL_ABAP_OBJECTDESCR | |--CL_ABAP_CLASSDESCR |--CL_ABAP_INTFDESCR TYPES elem_type TYPE c LENGTH 5.
DATA(tdo_elem) = CAST cl_abap_elemdescr(
cl_abap_typedescr=>describe_by_name( 'ELEM_TYPE' ) ).
DATA(rel_name) = tdo_elem->get_relative_name( ).
TYPES reftype TYPE REF TO string.
DATA(dref) = NEW i( 123 ).
DATA(type_descr1) = cl_abap_typedescr=>describe_by_data_ref( dref ).
DATA(tdo_ref) = CAST cl_abap_refdescr(
cl_abap_typedescr=>describe_by_name( 'REFTYPE' ) ).
DATA(type_descr2) = tdo_ref->get_referenced_type( ).
DATA structure TYPE zdemo_abap_carr.
DATA(tdo_struc) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_data( structure ) ).
DATA(abs_name) = tdo_struc->absolute_name.
DATA(struc_components) = tdo_struc->get_components( ).
DATA itab TYPE SORTED TABLE OF zdemo_abap_carr WITH UNIQUE KEY carrid.
DATA(tdo_itab) = CAST cl_abap_tabledescr(
cl_abap_typedescr=>describe_by_data( itab ) ).
DATA(keys) = tdo_itab->get_keys( ).
DATA(tab_components) = CAST cl_abap_structdescr( tdo_itab->get_table_line_type( ) )->components.
DATA(tdo_oref) = CAST cl_abap_classdescr(
cl_abap_typedescr=>describe_by_name( 'CL_ABAP_CLASSDESCR' ) ).
DATA(cl_methods) = tdo_oref->methods.
DATA(cl_attr) = tdo_oref->attributes.
DATA(tdo_iref) = CAST cl_abap_intfdescr(
cl_abap_typedescr=>describe_by_name( 'ZDEMO_ABAP_OBJECTS_INTERFACE' ) ).
DATA(intf_methods) = tdo_iref->methods.
DATA(intf_attr) = tdo_iref->attributes. |
Class | Details/Code Snippet |
CL_ABAP_CORRESPONDING |
For assignments of components between structures or between internal tables with dynamically specified mapping rules. For more information, you can refer to the ABAP Keyword Documentation.
The example shows simple assignments with structures.
DATA: BEGIN OF s1,
a TYPE i,
b TYPE c LENGTH 3,
c TYPE c LENGTH 5,
END OF s1.
DATA: BEGIN OF s2,
a TYPE i,
b TYPE c LENGTH 3,
d TYPE string,
END OF s2.
"Populating structures
s1 = VALUE #( a = 1 b = 'aaa' c = 'bbbbb' ).
s2 = VALUE #( a = 2 b = 'ccc' d = `dddd` ).
DATA(s3) = s1.
DATA(s4) = s2.
"Creating a mapping object
"An initial mapping table means that only identically named components are assigned.
"Other components retain their original values, i.e. the assignment for structures
"works like MOVE-CORRESPONDING or the CORRESPONDING operator with the BASE addition
DATA(map_obj) = cl_abap_corresponding=>create( source = s1
destination = s2
mapping = VALUE #( ) ).
"Performing the assignment
map_obj->execute( EXPORTING source = s1
CHANGING destination = s2 ).
*s2
*A B D
*1 aaa dddd
"Performing the assignment without extra variable; specifying the mapping table:
"level: 0 means the top level
"kind: 1 means that components specified in this line are mapped to each other;
" see the specification options in cl_abap_corresponding=>mapping_...
"srcname/dstname: source component/target component
cl_abap_corresponding=>create(
source = s3
destination = s4
mapping = VALUE #( ( level = 0 kind = 1 srcname = 'c' dstname = 'd' ) )
)->execute( EXPORTING source = s3
CHANGING destination = s4 ).
*s4
*A B D
*1 aaa bbbbb |
Class | Details/Code Snippet |
CL_ABAP_STRUCT_UTILITIES |
Provides methods to get information about filled components in structures allowing an efficient processing of non-initial components of a structure.
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
out->write( `---------- filled_components method ----------` ).
"It returns an internal table containing the names of the non-initial
"components of the structure and their index.
DATA: BEGIN OF struct,
a TYPE c LENGTH 1,
b TYPE i,
c TYPE zdemo_abap_carr,
d TYPE REF TO string,
END OF struct.
struct = VALUE #( a = 'X'
b = 123
c = VALUE #( carrid = 'LH' )
d = NEW #( `ABAP` ) ).
"Getting component information using RTTI
DATA(all_comps) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( struct ) )->components.
out->write( all_comps ).
"Getting an internal table containing the names of non-initial components
"and their index
DATA(filled_comps) = cl_abap_struct_utilities=>filled_components( struct ).
out->write( filled_comps ).
"In a loop, structure components are cleared. The filled_components method
"is called in each loop pass, visualizing the filled components in the
"structure.
DO lines( all_comps ) TIMES.
CLEAR struct-(sy-index).
filled_comps = cl_abap_struct_utilities=>filled_components( struct ).
out->write( filled_comps ).
ENDDO.
out->write( `---------- filled_components_c method ----------` ).
"Same as above. All structure components must be typed with c LENGTH 1.
DATA: BEGIN OF struct_c1,
a TYPE c LENGTH 1 VALUE 'X',
b TYPE c LENGTH 1,
c TYPE c LENGTH 1 VALUE 'X',
END OF struct_c1.
filled_comps = cl_abap_struct_utilities=>filled_components_c( struct_c1 ).
out->write( filled_comps ).
out->write( `---------- filled_components_x method ----------` ).
"Same as above. All structure components must be typed with x LENGTH 1.
"It is especially useful for checking filled components of BDEF derived types,
"for example, %control.
DATA struc_der_type TYPE STRUCTURE FOR READ IMPORT zdemo_abap_rap_ro_m.
struc_der_type = VALUE #( %control = VALUE #( key_field = if_abap_behv=>mk-on
field1 = if_abap_behv=>mk-on
field2 = if_abap_behv=>mk-off
field3 = if_abap_behv=>mk-off
field4 = if_abap_behv=>mk-on ) ).
filled_comps = cl_abap_struct_utilities=>filled_components_x( struc_der_type-%control ).
out->write( filled_comps ).
ENDMETHOD.
ENDCLASS. |
Class | Details/Code Snippet |
CL_ABAP_DIFF |
Using the methods diff and diff_with_line_ref of the CL_ABAP_DIFF class, you can compare the content of two compatible index tables. The returning parameter is an internal table showing how the content of one internal table can be modified to match another one. diff_with_line_ref also returns a reference to the original table lines. Various importing parameters are available to adjust the comparison. Find more information in the class documentation and in the ABAP Keyword Documentation.
CLASS zcl_demo_test DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_test IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
TYPES: BEGIN OF s,
a TYPE i,
b TYPE string,
c TYPE c LENGTH 3,
END OF s.
DATA it1 TYPE TABLE OF s WITH EMPTY KEY.
DATA it2 TYPE TABLE OF s WITH EMPTY KEY.
it1 = VALUE #(
( a = 1 b = `aaa` c = 'zzz' )
( a = 2 b = `bbb` c = 'yyy' )
( a = 3 b = `ccc` c = 'xxx' )
( a = 4 b = `ddd` c = 'www' )
).
it2 = VALUE #(
( a = 1 b = `aaa` c = 'zzz' )
( a = 2 b = `#bb` c = 'yy#' )
( a = 3 b = `cc` c = 'x' )
( a = 4 b = `ddd` c = 'www' )
( a = 5 b = `eee` c = 'vvv' )
).
DATA(it3) = it1.
DATA is_identical TYPE abap_bool.
DATA(comparison) = cl_abap_diff=>create( ).
TRY.
DATA(comp_res1) = comparison->diff( EXPORTING target = it2
source = it1
IMPORTING flag_identical = is_identical ).
IF is_identical = abap_true.
out->write( `The two internal tables have identical content.` ).
ELSE.
out->write( comp_res1 ).
ENDIF.
CATCH cx_abap_diff INTO DATA(error1).
out->write( error1->get_text( ) ).
ENDTRY.
TRY.
DATA(comp_res2) = comparison->diff_with_line_ref( EXPORTING target = it2
source = it1
IMPORTING flag_identical = is_identical ).
IF is_identical = abap_true.
out->write( `The two internal tables have identical content.` ).
ELSE.
out->write( comp_res2 ).
ENDIF.
CATCH cx_abap_diff INTO DATA(error2).
out->write( error2->get_text( ) ).
ENDTRY.
TRY.
DATA(comp_res3) = comparison->diff_with_line_ref( EXPORTING target = it3
source = it1
IMPORTING flag_identical = is_identical ).
IF is_identical = abap_true.
out->write( `The two internal tables have identical content.` ).
ELSE.
out->write( comp_res3 ).
ENDIF.
CATCH cx_abap_diff INTO DATA(error3).
out->write( error3->get_text( ) ).
ENDTRY.
ENDMETHOD.
ENDCLASS. |
Class | Details/Code Snippet |
CL_ABAP_DYN_PRG |
For validating input for dynamic specifications.
"The following method checks database table names. The name is provided
"with the val parameter. The packages formal parameter expects a table
"containing the names of packages in which the specified table should be
"included. Assuming you provide incorrect input for the table name, or
"the table is not contained in the specified packages, you can expect an
"exception to be raised.
TRY.
DATA(dbtab) = cl_abap_dyn_prg=>check_table_name_tab(
val = `ZDEMO_ABAP_FLI`
packages = VALUE #( ( `TEST_ABAP_CHEAT_SHEETS` )
( `TEST_SOME_PACK` ) ) ).
SELECT SINGLE * FROM (dbtab) INTO NEW @DATA(ref_wa).
CATCH cx_abap_not_a_table cx_abap_not_in_package.
...
ENDTRY.
"In the following examples, a method is used to check whether
"the input is allowed or not. For this, you specify an allowlist.
"Here, the relvant parameter expects a comma-separated list of
"allowed values.
TRY.
DATA(value1) = cl_abap_dyn_prg=>check_allowlist(
val = `A`
allowlist_str = `A,B,C,D` ).
... "Here might go an ABAP SQL statement with a dynamic specification.
CATCH cx_abap_not_in_allowlist.
...
ENDTRY.
"Another parameter of the method expects an internal table that
"contains the allowed values.
TRY.
DATA(value2) = cl_abap_dyn_prg=>check_allowlist(
val = `XYZ`
allowlist_htab = VALUE #( ( `A` )
( `B` )
( `C` )
( `D` ) ) ).
... "Here might go an ABAP SQL statement with a dynamic specification.
CATCH cx_abap_not_in_allowlist.
...
ENDTRY. |
Class | Details/Code Snippet |
CL_ABAP_CONTEXT_INFO |
Provides context information relevant to the current ABAP session.
"Getting current date in UTC (not the system or user time), e.g. 20240101
DATA(sys_date) = cl_abap_context_info=>get_system_date( ).
"Getting current time in UTC, e.g. 152450
DATA(sys_time) = cl_abap_context_info=>get_system_time( ).
"User alias, e.g. XY0000001234
DATA(alias) = cl_abap_context_info=>get_user_alias( ).
"You can also get user information using XCO classes
DATA(user_w_xco) = xco_cp=>sy->user( )->name.
"Formatted name, e.g. John Doe
TRY.
DATA(formatted_name) = cl_abap_context_info=>get_user_formatted_name( ).
CATCH cx_abap_context_info_error.
ENDTRY. |
Class | Details |
CL_IXML_* CL_SXML_* |
"As mentioned, refer to the ABAP Keyword Documentation and the
"XML/JSON cheat sheet (and executable example) for examples
"Creating an XML writer using sXML
DATA(writer) = CAST if_sxml_writer( cl_sxml_string_writer=>create( type = if_sxml=>co_xt_xml10
encoding = 'UTF-8' ) ).
"The above writer uses a cast to if_sxml_writer. In doing so,
"more special methods can be accessed. You can check it by adding
"the object component selector (->) behind the closing parenthesis.
"Plus: The example above specifies the default parameters
"explicitly. Here, they are omitted. You can also create a JSON
"writer.
DATA(writer2) = cl_sxml_string_writer=>create( ).
... "Creating some XML data
"Creating an XML reader using sXML
"Note: Similar to the writer, the interface IF_SXML_READER exists
"for readers.
DATA(reader) = cl_sxml_string_reader=>create( some_xml ).
... "Reading XML data sequentially |
XCO_CP_JSON |
Handling JSON data using the XCO library
"Creating and populating a demo structure and internal table
DATA: BEGIN OF carrier_struc,
carrier_id TYPE c length 3,
connection_id TYPE n length 4,
city_from TYPE c length 20,
city_to TYPE c length 20,
END OF carrier_struc.
DATA carriers_tab LIKE TABLE OF carrier_struc WITH EMPTY KEY.
carrier_struc = VALUE #( carrier_id = 'AA' connection_id = '17' city_from = 'New York' city_to = 'San Francisco' ).
carriers_tab = VALUE #( ( carrier_id = 'AZ' connection_id = '788' city_from = 'Rome' city_to = 'Tokyo' )
( carrier_id = 'JL' connection_id = '408' city_from = 'Frankfurt' city_to = 'Tokyo' ) ).
"ABAP (structure) -> JSON using XCO
DATA(struc2json_xco) = xco_cp_json=>data->from_abap( carrier_struc )->to_string( ).
"Result: {"CARRIER_ID":"AA","CONNECTION_ID":"0017","CITY_FROM":"New York","CITY_TO":"San Francisco"}
"ABAP (internal table) -> JSON using XCO
DATA(itab2json_xco) = xco_cp_json=>data->from_abap( carriers_tab )->to_string( ).
"Result: [{"CARRIER_ID":"AZ","CONNECTION_ID":"0788","CITY_FROM":"Rome","CITY_TO":"Tokyo"},
" {"CARRIER_ID":"JL","CONNECTION_ID":"0408","CITY_FROM":"Frankfurt","CITY_TO":"Tokyo"}]
"JSON -> ABAP (structure) using XCO
DATA json2struc_xco LIKE carrier_struc.
xco_cp_json=>data->from_string( struc2json_xco )->write_to( REF #( json2struc_xco ) ).
"Result:
"CARRIER_ID CONNECTION_ID CITY_FROM CITY_TO
"AA 0017 New York San Francisco
"JSON -> ABAP (internal table) using XCO
DATA json2itab_xco LIKE carriers_tab.
xco_cp_json=>data->from_string( itab2json_xco )->write_to( REF #( json2itab_xco ) ).
"Result:
"CARRIER_ID CONNECTION_ID CITY_FROM CITY_TO
"AZ 0788 Rome Tokyo
"JL 0408 Frankfurt Tokyo
"Creating JSON using XCO
"You can check out more methods that offer various options to build
"the JSON by clicking CTRL + Space after '->' in ADT.
"In the following example, JSON data similar to above is created.
"First, a JSON data builder is created. Then, using different methods,
"JSON data is created.
DATA(json_builder_xco) = xco_cp_json=>data->builder( ).
json_builder_xco->begin_object(
)->add_member( 'CarrierId' )->add_string( 'DL'
)->add_member( 'ConnectionId' )->add_string( '1984'
)->add_member( 'CityFrom' )->add_string( 'San Francisco'
)->add_member( 'CityTo' )->add_string( 'New York'
)->end_object( ).
"Getting JSON data
DATA(json_created_xco) = json_builder_xco->get_data( )->to_string( ).
"Result: {"CarrierId":"DL","ConnectionId":"1984","CityFrom":"San Francisco","CityTo":"New York"}
"Transforming the created JSON to ABAP (structure)
"Note: The JSON was intentionally created without the underscores in the
"name to demonstrate the 'apply' method. The following example demonstrates
"a transformation of camel case and underscore notation. As above, check out
"more options by clicking CTRL + Space after '...transformation->'.
CLEAR json2struc_xco.
xco_cp_json=>data->from_string( json_created_xco )->apply( VALUE #(
( xco_cp_json=>transformation->pascal_case_to_underscore ) ) )->write_to( REF #( json2struc_xco ) ).
"Result
"CARRIER_ID CONNECTION_ID CITY_FROM CITY_TO
"DL 1984 San Francisco New York |
/UI2/CL_JSON |
DATA(some_table) = VALUE string_table( ( `aaa` ) ( `bbb` ) ( `ddd` ) ).
"--------- ABAP -> JSON ---------
DATA(abap_to_json) = /ui2/cl_json=>serialize( data = some_table ).
"--------- JSON -> ABAP ---------
DATA table_json_to_abap TYPE string_table.
/ui2/cl_json=>deserialize( EXPORTING json = abap_to_json
CHANGING data = table_json_to_abap ). |
Class | Details/Code Snippet |
XCO_CP_ABAP XCO_CP_ABAP_REPOSITORY |
"Getting all accessible repository objects in the system
"To further process the returned values, you can loop over them.
DATA(all_obj) = xco_cp_abap_repository=>objects->all->in( xco_cp_abap=>repository )->get( ).
"Gettig all database tables
DATA(all_tables) = xco_cp_abap_repository=>objects->tabl->all->in( xco_cp_abap=>repository )->get( ).
"Refining the search by applying a filter
"Creating a filter and adding a search pattern
DATA(filter1) = xco_cp_abap_repository=>object_name->get_filter(
xco_cp_abap_sql=>constraint->contains_pattern( 'ZDEMO_ABAP_RAP_R%' ) ).
"Getting all BDEFs in the system having a specific pattern
DATA(bdefs_in_package) = xco_cp_abap_repository=>objects->bdef->where( VALUE #( ( filter1 )
) )->in( xco_cp_abap=>repository )->get( ).
"Getting all accessible interfaces with a particular name pattern in the entire system
DATA(filter2) = xco_cp_abap_repository=>object_name->get_filter(
xco_cp_abap_sql=>constraint->contains_pattern( 'IF_ABAP_BEHV%' ) ).
DATA(all_intfs) = xco_cp_abap_repository=>objects->intf->where( VALUE #( ( filter2 )
) )->in( xco_cp_abap=>repository )->get( ).
"Getting all classes in the system that correspond to a specific name pattern and
"that are contained in a specific software component
"Creating filters
DATA(filter3) = xco_cp_system=>software_component->get_filter( xco_cp_abap_sql=>constraint->equal( 'SAP_BASIS' ) ).
DATA(filter4) = xco_cp_abap_repository=>object_name->get_filter( xco_cp_abap_sql=>constraint->contains_pattern( '%CL_ABAP_RAND%' ) ).
DATA(filtered_classes) = xco_cp_abap_repository=>objects->clas->where( VALUE #( ( filter3 ) ( filter4 )
) )->in( xco_cp_abap=>repository )->get( ).
"Getting information about some of the technical properties of different
"repository objects. The examples show the creation of handlers. You can
"explore more options, e.g., by adding the object component selector (->)
"to the final parenthesis and checking the suggestions by ADT.
"Database table
DATA(handler_tabl) = xco_cp_abap_dictionary=>database_table( 'ZDEMO_ABAP_CARR' ).
"Data element
DATA(handler_dtel) = xco_cp_abap_dictionary=>data_element( 'MANDT' ).
"Table type
DATA(handler_table_type) = xco_cp_abap_dictionary=>table_type( 'STRING_TABLE' ).
"CDS view entity
DATA(handler_cds_ve) = xco_cp_cds=>view_entity( 'ZDEMO_ABAP_RAP_RO_M' ).
"Interface
DATA(handler_intf) = xco_cp_abap=>interface( 'ZDEMO_ABAP_OBJECTS_INTERFACE' ).
"Getting information about where the interface is implemented
DATA(where_is_intf_impl) = handler_intf->implementations->all->get_names( ).
"Class
DATA(handler_cl) = xco_cp_abap=>class( 'ZCL_DEMO_ABAP_UNIT_TEST' ).
"Getting subclasses
DATA(subcl) = xco_cp_abap=>class( 'CL_ABAP_TYPEDESCR' )->subclasses->all->get( ).
"Getting the names of the subclasses
DATA(subcl_names) = xco_cp_abap=>class( 'CL_ABAP_TYPEDESCR' )->subclasses->all->get_names( ).
"Getting the direct superclass
DATA(direct_super_class) = xco_cp_abap=>class( 'CL_ABAP_DATADESCR' )->definition->content(
)->get_superclass( )->name.
"Taking an XCO handler for a database table as an example, see some of the
"details you can retrieve. The method names should be self-explanatory.
DATA(dbtab_name) = handler_tabl->name.
DATA(dbtab_descr) = handler_tabl->content( )->get_short_description( ).
DATA(dbtab_del_cl) = handler_tabl->content( )->get_delivery_class( )->value.
DATA(dbtab_field_names) = handler_tabl->fields->all->get_names( ).
DATA(dbtab_keys) = handler_tabl->fields->key->get_names( ).
DATA(dbtab_vis) = handler_tabl->get_api_state( )->get_visibilities( ). "Initial for the cheat sheet table
DATA(dbtab_rel_state) = handler_tabl->get_api_state( )->get_release_state( )->value. |
Class | Details/Code Snippet |
XCO_CP_GENERATION |
For creating, updating and deleting ABAP repository objects. More information: Generation APIs The rudimentary snippet is taken from the executable example of the ABAP for Cloud Development cheat sheet. ...
DATA(n10_handler) = xco_cp_generation=>environment->dev_system( ... ).
DATA(n11_put) = n10_handler->create_put_operation( ).
"Creating a domain
DATA(n12_doma_spec) = n11_put->for-doma->add_object( ... "e.g. 'ZDEMO_ABAP_STATUS'
)->set_package( ...
)->create_form_specification( ).
n12_doma_spec->set_short_description( 'Demo domain' ).
n12_doma_spec->set_format( xco_cp_abap_dictionary=>built_in_type->char( 10 ) ).
n12_doma_spec->fixed_values->add_fixed_value( 'BOOKED'
)->set_description( 'Booked' ).
n12_doma_spec->fixed_values->add_fixed_value( 'CANCELED'
)->set_description( 'Canceled' ).
...
"Executing the generation
TRY.
n11_put->execute( ).
CATCH cx_xco_gen_put_exception.
ENDTRY. |
Class | Details/Code Snippet |
XCO_CP XCO_CP_CALL_STACK |
Getting the current ABAP call stack programmatically. See more information here.
"Getting the full current call stack
DATA(call_stack) = xco_cp=>current->call_stack->full( ).
"Creating a format for the call stack
"In the example, an ADT debugger-like style is used
DATA(format) = xco_cp_call_stack=>format->adt(
)->with_line_number_flavor( xco_cp_call_stack=>line_number_flavor->source ).
"Retrieving the full call stack as text, e.g. so that it can be output
"or written somewhere
DATA(call_stack_as_text) = call_stack->as_text( format ).
"Extracting the call stack based on specifications
"You can specify the extractions using from/to and
"further detailing out the kinds of extractions
"such as the position or the first/last occurrence
"of a specific line pattern.
"In the example, a line pattern is created (method that
"starts with a specific pattern). The extracting should
"go up to the last occurrence of this pattern. It is
"started at position 1.
DATA(line_pattern) = xco_cp_call_stack=>line_pattern->method(
)->where_class_name_starts_with( 'CL_REST' ).
DATA(extracted_call_stack_as_text) = call_stack->from->position( 1
)->to->last_occurrence_of( line_pattern )->as_text( format ). |
Class | Details/Code Snippet |
CL_BCS_MAIL_MESSAGE |
TRY.
DATA(mail) = cl_bcs_mail_message=>create_instance( ).
mail->set_sender( '...@...' ).
mail->add_recipient( '...@...' ).
mail->set_subject( 'Test Mail' ).
mail->set_main( cl_bcs_mail_textpart=>create_instance(
iv_content = '<h1>Hello</h1><p>This is a test mail.</p>'
iv_content_type = 'text/html' ) ).
mail->send( IMPORTING et_status = DATA(status_table) ).
"You can check the status of the email sending in the returned table.
"'status' components: E (error), S (sent), W (waiting)
CATCH cx_bcs_mail INTO DATA(error_mail).
...
ENDTRY. |
Class | Details/Code Snippet |
XCO_CP XCO_CP_TENANT |
For obtaining various information about the currently active tenant.
"Getting a handler for the currently active tenant
DATA(ten) = xco_cp=>current->tenant( ).
"Getting the UI URL of the currently active tenant
DATA(ui_url) = ten->get_url( xco_cp_tenant=>url_type->ui ).
"Protocol
"e.g. https
DATA(prot) = ui_url->get_protocol( ).
"Host and domain
"e.g. abcde-...-com
DATA(host) = ui_url->get_host( ).
"Port
"e.g. 443
DATA(port) = ui_url->get_port( ).
"Global account ID
DATA(global_acc_id) = ten->get_global_account_id( )->as_string( ).
"Guid
DATA(guid) = ten->get_guid( )->value.
"Id
DATA(id) = ten->get_id( ).
"Subaccount ID
DATA(sub_acc_id) = ten->get_subaccount_id( )->as_string( ). |
Class | Details/Code Snippet |
CX_* |
Exception classes are special classes, usually starting with the name CX_* , that serve as the basis for catchable exceptions. When an exception is raised, an object of such an exception class is created. There are several predefined exception classes. Find more information in the cheat sheet about program flow logic.
TRY.
DATA(res) = 1 / 0.
CATCH cx_sy_zerodivide.
ENDTRY.
DATA(str_table) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ).
TRY.
DATA(table_entry) = str_table[ 4 ].
CATCH cx_sy_itab_line_not_found.
ENDTRY. |
Class | Details/Code Snippet |
CL_ABAP_PARALLEL |
For performing the parallel processing for instances of ABAP Objects. The following example class is intended to be a self-contained example that tries to visualize the functionality of the CL_ABAP_PARALLEL class. For more information, refer to the class documentation.
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES if_abap_parallel.
METHODS: constructor.
PRIVATE SECTION.
"This table holds entries that are added when
"calling the 'do' method.
DATA info_parallel_proc TYPE string_table.
"Data types and objects for the data cluster
"that contains information to be output
CLASS-DATA buffer TYPE xstring.
DATA obj TYPE string.
DATA parallel_log TYPE string_table.
DATA inst_name TYPE string.
"Structure to hold information for the output
DATA: BEGIN OF info,
name TYPE string,
tmstmp TYPE utclong,
END OF info.
"Preparing the data cluster
METHODS handle_cluster IMPORTING name TYPE string.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"This is a self-contained example class trying to visualize the
"functionality of the cl_abap_parallel class.
"As a prerequisite, you have a class that implements the interface
"IF_ABAP_PARALLEL. In the self-contained example, it is this class
"itself that implements it.
"When running the class with F9, the following code is executed.
"Creating an instance of class cl_abap_parallel
DATA(parallel) = NEW cl_abap_parallel( ).
"Creating instances of this example class for demonstration
"purposes. The handle_cluster method is used to manually
"provide the name of the object reference variable for
"output purposes.
handle_cluster( `inst1` ).
DATA(inst1) = NEW zcl_some_class( ).
handle_cluster( `inst2` ).
DATA(inst2) = NEW zcl_some_class( ).
handle_cluster( `inst3` ).
DATA(inst3) = NEW zcl_some_class( ).
handle_cluster( `inst4` ).
DATA(inst4) = NEW zcl_some_class( ).
WAIT UP TO 1 SECONDS.
"Starting the parallel processing for objects with the 'run_inst' method.
"As input parameters, instances of the classes to be processed are expected.
"The importing parameter is an internal table. It contains result information
"for the tasks that were processed in parallel.
parallel->run_inst( EXPORTING p_in_tab = VALUE #( ( inst1 )
( inst2 )
( inst3 )
( inst4 ) )
IMPORTING p_out_tab = DATA(result_info) ).
WAIT UP TO 1 SECONDS.
LOOP AT result_info INTO DATA(wa).
"For accessing the details, a cast to the respective class is required (in this
"case, it is this very class).
DATA(res) = CAST zcl_some_class( wa-inst ).
"Adding information to a string table that is output
APPEND |**** Instance "{ res->info-name }" created at { res->info-tmstmp } ****| TO parallel_log.
LOOP AT res->info_parallel_proc INTO DATA(wap).
APPEND |{ wap }| TO parallel_log.
ENDLOOP.
APPEND `-----------------------------------------------------------------` TO parallel_log.
ENDLOOP.
out->write( parallel_log ).
ENDMETHOD.
METHOD if_abap_parallel~do.
"The following code is executed in parallel.
"In the simplified example, some text is added to a string table that
"is output later on. It includes a time stamp to compare the different
"outputs.
DO 3 TIMES.
APPEND |This text was added at { utclong_current( ) }| TO info_parallel_proc.
ENDDO.
ENDMETHOD.
METHOD constructor.
"The purpose of the implementation in the instance constructor
"is to pass the manually added name of the object reference
"variable for output purposes.
"A data cluster is used to have a self-contained example class
"that can be run with F9.
TRY.
IMPORT str = inst_name FROM DATA BUFFER buffer.
CATCH cx_sy_import_format_error INTO DATA(error).
ENDTRY.
IF error IS INITIAL.
"The information provided here is used for output purposes.
"The name of the object reference variable is
"expected to be the only input in the table, as well as
"a time stamp to compare with other time stamps that are
"output.
info = VALUE #( name = inst_name
tmstmp = utclong_current( ) ).
ENDIF.
ENDMETHOD.
METHOD handle_cluster.
"This method is used to prepare the data cluster and
"pass the name of the object reference variable that
"was added manually via the input parameter 'name'.
CLEAR buffer.
obj = name.
EXPORT str = obj TO DATA BUFFER buffer.
ENDMETHOD.
ENDCLASS. |
Class | Details/Code Snippet |
CL_BALI_LOG |
For creating and reading application logs. Refer to this documentation for more information and code snippets. Note that there is also an XCO module available dealing with business application log (XCO_CP_BAL ; see this documentation).
"Demo application job (sub)objects and external ID
"Note:
"- Refer to the documentation about how to create an application log object in ADT,
" and for more options the classes offer in the context of application logs.
"- Required authorization for authorization object: S_APPL_LOG.
CONSTANTS: obj TYPE cl_bali_header_setter=>ty_object VALUE 'DEMO_LOG',
subobj TYPE cl_bali_header_setter=>ty_subobject VALUE 'DEMO_SUB',
external_id TYPE cl_bali_header_setter=>ty_external_id VALUE 'DEMO_EXT_ID'.
"---- Creating (and deleting) application log entries ----
TRY.
"Creating an instance of the application Log class
DATA(appl_log) = cl_bali_log=>create( ).
"Setting the header log, using application log object descriptions
appl_log->set_header( header = cl_bali_header_setter=>create( object = obj
subobject = subobj
external_id = external_id ) ).
"Before creating new application log entries, deleting existing ones based on the application
"log object information and the user
DATA(filter4del) = cl_bali_log_filter=>create( ).
filter4del->set_create_info( user = xco_cp=>sy->user( )->name
)->set_descriptor( object = obj
subobject = subobj
external_id = external_id ).
"Reading the logs from the database by applying the filter
DATA(del_appl_log) = cl_bali_log_db=>get_instance( )->load_logs_w_items_via_filter( filter = filter4del ).
"Deleting existing application log entries that are retrieved based on the applied filter
LOOP AT del_appl_log INTO DATA(log_del).
cl_bali_log_db=>get_instance( )->delete_log( log = log_del ).
ENDLOOP.
CATCH cx_bali_runtime.
ENDTRY.
TRY.
"Creating new application log entries
"Creating a free text and adding it to the application log
DATA(free_txt) = cl_bali_free_text_setter=>create( severity = if_bali_constants=>c_category_free_text
text = |This text is added to the application log at { utclong_current( ) }| ).
appl_log->add_item( item = free_txt ).
"Creating an exception and adding it to the application log
DATA(strtab) = VALUE string_table( ( `a` ) ( `b` ) ( `c` ) ).
TRY.
DATA(line) = strtab[ 4 ].
CATCH cx_sy_itab_line_not_found INTO DATA(error).
ENDTRY.
DATA(exc) = cl_bali_exception_setter=>create( severity = if_bali_constants=>c_category_exception
exception = error ).
appl_log->add_item( item = exc ).
"Saving the application log to the database
cl_bali_log_db=>get_instance( )->save_log( log = appl_log ).
CATCH cx_bali_runtime.
ENDTRY.
WAIT UP TO 1 SECONDS.
"---- Reading the application log ----
TRY.
"Creating a filter
"Only the messages from the current user based on the application log
"object information and in the time frame now - 1 hour are retrieved.
DATA(filter) = cl_bali_log_filter=>create( ).
DATA(now) = utclong_current( ).
DATA(anhourearlier) = utclong_add( val = now
hours = '1-' ).
filter->set_create_info( user = xco_cp=>sy->user( )->name
)->set_descriptor( object = obj
subobject = subobj
external_id = external_id
)->set_time_interval( start_time = anhourearlier
end_time = now ).
"Reading the logs from the database by applying the filter
DATA(log_table) = cl_bali_log_db=>get_instance( )->load_logs_w_items_via_filter( filter = filter ).
"Processing the read result
LOOP AT log_table INTO DATA(log).
"Retrieving all items
DATA(items) = log->get_all_items( ).
"Retrieving the application log messages (and displaying)
LOOP AT items INTO DATA(item).
DATA(log_item_number) = item-log_item_number.
DATA(msg) = item-item->get_message_text( ).
"Displaying the entries when running a class
"that implements the if_oo_adt_classrun interface
"out->write( |{ log_item_number } { msg }| ).
ENDLOOP.
ENDLOOP.
CATCH cx_bali_runtime.
ENDTRY. |
Class | Details/Code Snippet |
CL_BGMC_PROCESS_FACTORY |
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES if_bgmc_op_single_tx_uncontr.
CLASS-METHODS get_uuid RETURNING VALUE(uuid) TYPE sysuuid_x16.
PRIVATE SECTION.
CLASS-DATA number TYPE i.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"Deleting a demo database table
DELETE FROM zdemo_abap_tabca.
number += 1.
MODIFY zdemo_abap_tabca FROM @( VALUE #(
id = get_uuid( )
calc_result = |Synchronous entry creation in the MAIN method { number }|
crea_date_time = cl_abap_tstmp=>utclong2tstmp( utclong_current( ) ) ) ).
"Processing code in the background
DO 2 TIMES.
"Creating an instance of the example class (that implements the bgPF-relevant
"interface if_bgmc_op_single_tx_uncontr)
DATA(inst) = NEW zcl_some_class( ).
TRY.
"Getting the default factory for transactional background processes and
"creating a process for a single operation
DATA(backgr) = cl_bgmc_process_factory=>get_default( )->create( ).
"Setting a name of the process
backgr->set_name( `bgPF Test` ).
"Setting the transactionally uncontrolled operation of the process
backgr->set_operation_tx_uncontrolled( inst ).
"Saving the background process for the asynchronous execution
backgr->save_for_execution( ).
"An explicit COMMIT WORK is required to start the background process.
"This explicit call is not needed in the context of RAP because the RAP
"framework will take care of the commit call.
COMMIT WORK.
CATCH cx_bgmc INTO DATA(error).
out->write( error->get_text( ) ).
ROLLBACK WORK.
ENDTRY.
number += 1.
MODIFY zdemo_abap_tabca FROM @( VALUE #(
id = get_uuid( )
calc_result = |Synchronous entry creation in the MAIN method { number }|
crea_date_time = cl_abap_tstmp=>utclong2tstmp( utclong_current( ) ) ) ).
WAIT UP TO 1 SECONDS.
ENDDO.
WAIT UP TO 2 SECONDS.
"Displaying the content of a demo database table that was filled
"in the course of the class execution
SELECT id, calc_result, crea_date_time
FROM zdemo_abap_tabca
ORDER BY crea_date_time
INTO TABLE @DATA(itab).
out->write( itab ).
ENDMETHOD.
METHOD if_bgmc_op_single_tx_uncontr~execute.
MODIFY zdemo_abap_tabca FROM @( VALUE #(
id = get_uuid( )
calc_result = `Asynchronous entry creation in background in the EXECUTE method`
crea_date_time = cl_abap_tstmp=>utclong2tstmp( utclong_current( ) ) ) ).
ENDMETHOD.
METHOD get_uuid.
TRY.
uuid = cl_system_uuid=>create_uuid_x16_static( ) .
CATCH cx_uuid_error.
ENDTRY.
ENDMETHOD.
ENDCLASS. |
Class | Details/Code Snippet |
CL_ABAP_LOCK_OBJECT_FACTORY |
For activating lock objects. Note that you can also use the DEQUEUE_ALL method to remove all locks in the current SAP LUW.
The following example code snippet uses artifacts from the ABAP cheat sheet repository.
"Deleting demo database table
DELETE FROM zdemo_abap_rapt1.
"Creating a database table entry and reading it into a data reference variable
MODIFY zdemo_abap_rapt1 FROM @( VALUE #( key_field = 1 field1 = 'aaa' field2 = 'bbb' field3 = 2 field4 = 3 ) ).
SELECT SINGLE * FROM zdemo_abap_rapt1 WHERE key_field = 1 INTO NEW @DATA(key).
TRY.
"Instantiating a lock object
DATA(lock) = cl_abap_lock_object_factory=>get_instance( iv_name = 'EZDEMO_ABAP_LOCK' ).
"Enqueuing a lock object
"Note that there are various parameters. The parameter used in the example contains
"a list of lock fields including a reference to the parameter value.
lock->enqueue( it_parameter = VALUE #( ( name = 'KEY_FIELD' value = REF #( key->key_field ) ) ) ).
CATCH cx_abap_lock_failure cx_abap_foreign_lock INTO DATA(enq_error).
ENDTRY.
TRY.
"Dequeuing a lock object
lock->dequeue( it_parameter = VALUE #( ( name = 'KEY_FIELD' value = REF #( key->key_field ) ) ) ).
CATCH cx_abap_lock_failure INTO DATA(deq_error).
ENDTRY. |
Class | Details/Code Snippet |
CL_WEB_HTTP_CLIENT_MANAGER CL_HTTP_DESTINATION_PROVIDER |
To check out examples in demo classes, expand the collapsible sections below. 1. Read example: Getting Markdown content and sending ZIP file via email
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
"Markdown URLs
CONSTANTS url_cs TYPE string VALUE `https://api.github.com/repos/SAP-samples/abap-cheat-sheets/git/trees/main`.
CONSTANTS url_gh TYPE string VALUE `https://raw.githubusercontent.com/SAP-samples/abap-cheat-sheets/main/`.
"Here go email addresses
CONSTANTS sender_addr TYPE cl_bcs_mail_message=>ty_address VALUE '...@...'.
CONSTANTS recipient_addr TYPE cl_bcs_mail_message=>ty_address VALUE '...@...'.
TYPES: BEGIN OF s,
file_name TYPE string,
markdown TYPE string,
error TYPE abap_boolean,
END OF s.
DATA tab TYPE TABLE OF s WITH EMPTY KEY.
DATA url TYPE string.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"----------- Retrieving all Markdown file names in the ABAP cheat sheet GitHub repository -----------
TRY.
"Creating a client object using a destination
"In the example, the HTTP destination is created using a plain URL.
"Here, a GitHub API is used to retrieve file names of the ABAP cheat sheet repository.
DATA(http_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( i_url = url_cs ) ).
"Sending an HTTP GET request and returning the response
"In the example, the HTTP body is retrieved as string data.
DATA(response) = http_client->execute( if_web_http_client=>get )->get_text( ).
IF response CS `API rate limit exceeded`.
out->write( `API rate limit exceeded` ).
RETURN.
ENDIF.
CATCH cx_root INTO DATA(err).
out->write( err->get_text( ) ).
RETURN.
ENDTRY.
"----------- Retrieving Markdown content from ABAP cheat sheet GitHub repository -----------
IF err IS INITIAL.
"Markdown file names are contained in the returned string in a specific
"pattern. In the following code, the markdown file names are extracted
"using a regular expression (pattern: "path":"04_ABAP_Object_Orientation.md")
"After '"path":"' (not including this part, indivated by \K), two
"digits must follow. Then, the further file name is captured with a
"non-greedy capturing up to '.md'.
FIND ALL OCCURRENCES OF PCRE `("path":")\K\d\d.*?\.md` IN response
RESULTS DATA(results)
IGNORING CASE.
"The 'results' internal table contains all findings and includes their
"offset and length information.
"Using a loop, the actual file names are extracted from the 'response'
"string and added to an internal table that is to receive more information
"in the code below.
LOOP AT results REFERENCE INTO DATA(md).
tab = VALUE #( BASE tab ( file_name = substring( val = response off = md->offset len = md->length ) ) ).
ENDLOOP.
SORT tab BY file_name ASCENDING.
"In the following loop, the Markdown content is retrieved using an HTTP GET request, also
"by creating a client object and using a destination (another plain URL). The URL is constructed
"using the constant value plus the markdown file that was retrieved before.
LOOP AT tab REFERENCE INTO DATA(cs).
url = url_gh && cs->file_name.
TRY.
http_client = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( i_url = url ) ).
DATA(raw_md) = http_client->execute( if_web_http_client=>get )->get_text( ).
cs->markdown = raw_md.
CATCH cx_root.
cs->error = abap_true.
ENDTRY.
ENDLOOP.
"----------- Creating a zip file containing all ABAP cheat sheet Markdown documents -----------
DATA(zip) = NEW cl_abap_zip( ).
"Iteratively adding the ABAP cheat sheet Markdown documents to the zip file
LOOP AT tab REFERENCE INTO cs WHERE error = abap_false.
TRY.
DATA(conv_xstring) = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( cs->markdown ).
CATCH cx_sy_conversion_codepage.
ENDTRY.
"Adding the xstring content as file content to zip
zip->add( name = cs->file_name
content = conv_xstring ).
ENDLOOP.
"Saving the zip file
DATA(zipped_file) = zip->save( ).
"----------- Creating a ZIP file containing all ABAP cheat sheet Markdown documents -----------
"Sending email
TRY.
"Creating a new mail instance
DATA(mail) = cl_bcs_mail_message=>create_instance( ).
"Settings
mail->set_sender( sender_addr ).
mail->add_recipient( recipient_addr ).
mail->set_subject( 'Test Mail' ).
"Main document
mail->set_main( cl_bcs_mail_textpart=>create_instance(
iv_content = '<h3>Test Mail</h3><p>Please find ABAP cheat sheet markdown files attached.<br>Cheers</p>'
iv_content_type = 'text/html' ) ).
"Adding an attachment
mail->add_attachment( cl_bcs_mail_binarypart=>create_instance(
iv_content = zipped_file
iv_content_type = 'application/x-zip-compressed'
iv_filename = 'abap_cheat_sheets.zip' ) ).
"Sending mail synchronously, displaying the status for each recipient
mail->send( IMPORTING et_status = DATA(status_table) ).
out->write( status_table ).
CATCH cx_bcs_mail INTO DATA(error_mail).
out->write( |Mail sending error: { error_mail->get_text( ) }| ).
ENDTRY.
ENDIF.
ENDMETHOD.
ENDCLASS. 2. Post example: Demonstrating a post request by converting Markdown to HTML using the GitHub API
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
CONSTANTS url_api TYPE string VALUE `https://api.github.com/markdown`.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(markdown_content) =
`# Lorem ipsum dolor sit amet \n` &&
`Consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \n` &&
`Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. \n` &&
`- Duis aute irure \n` &&
`- Dolor in reprehenderit in voluptate \n` &&
`1. Velit esse cillum dolore eu fugiat nulla pariatur \n` &&
`2. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. \n` &&
`3. [ABAP cheat sheets](https://github.com/SAP-samples/abap-cheat-sheets)`.
TRY.
"Creation of a client object using a destination
"This example deals with a POST request.
DATA(http_client) = cl_web_http_client_manager=>create_by_http_destination( i_destination = cl_http_destination_provider=>create_by_url( i_url = url_api ) ).
DATA(request) = http_client->get_http_request( ).
request->set_text( `{"text":"` && markdown_content && `"}` ).
request->set_header_fields( VALUE #( ( name = 'Accept' value = 'application/vnd.github+json' ) ) ).
DATA(post) = http_client->execute( if_web_http_client=>post ).
DATA(status) = post->get_status( ).
IF status-code <> 200.
out->write( |Post request error: { status-code } / { status-reason }| ).
ELSE.
DATA(html) = post->get_text( ).
out->write( html ).
ENDIF.
CATCH cx_root INTO DATA(error).
out->write( error->get_text( ) ).
ENDTRY.
ENDMETHOD.
ENDCLASS. |
Class | Details/Code Snippet |
XCO_CP_XLSX |
The XCO library offers classes such as
Expand the following collapsible section to view the steps and code of the example. Expand to view the detailsPrerequisite Steps for the XLSX Content Import into the SAP BTP ABAP Environment The XLSX XCO module works with XLSX content in the form of an xstring. The following example assumes that you have XLSX content available as xstring. To try out the example, you can proceed as follows:
Exploring the XCO XLSX Module Assuming you have the XLSX content created and uploaded above on your system, you can explore the following example using the XCO classes/methods. Set up a demo class called
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"As a prerequisite, you have walked through the steps mentioned. RAP repository objects
"were created, adapted as mentioned, and activated. You have at least one XLSX file imported
"using the preview app. XLSX content is available in the database table as xstring.
"--------------------------------------- NOTE ----------------------------------------
"------ This is only intended for demonstration purposes!! Do note the security ------
"------ aspects etc. when importing external content. The focus of this example ------
"------ is to explore the XCO XLSX module. ------------------------------------------
"The SELECT statement assumes there is one entry available. Otherwise, adapt the
"statement accordingly, e.g. by adding a WHERE clause and providing the UUID you can
"copy for a created entry in the Fiori Elements preview app. Note the XCO class with
"which to transform the UUID. Replace the dummy UUID.
SELECT SINGLE id, file_content FROM ztdemo_abap_xlsx
"WHERE id = @( CONV sysuuid_c32(
" xco_cp_uuid=>format->c32->from_uuid( xco_cp_uuid=>format->c36->to_uuid( 'a1a2a3a4-b1b2-c1c2-d3d4-e5e6e7e8e9e0' ) ) ) )
INTO @DATA(xlsx).
IF sy-subrc <> 0 OR xlsx-file_content IS INITIAL.
out->write( `No XLSX content available to work with` ).
RETURN.
ENDIF.
out->write( `Exploring reading and writing XLSX content with the XCO library` ).
out->write( |\n\n| ).
out->write( `-------------------- Read access to XLSX content --------------------` ).
out->write( |\n\n| ).
"Note: Using method chaining, the following method calls can also be done in a more concise way.
"As a first step (for reading and writing XLSX content), getting a handle to process
"XLSX content, which is available as xstring.
DATA(xlsx_doc) = xco_cp_xlsx=>document->for_file_content( xlsx-file_content ).
"------------------------ Read access to XLSX content ------------------------
"Getting read access
DATA(read_xlsx) = xlsx_doc->read_access( ).
"Reading the first worksheet of the XLSX file
DATA(worksheet1) = read_xlsx->get_workbook( )->worksheet->at_position( 1 ).
"You can also specify the name of the worksheet
"DATA(worksheet1) = read_xlsx->get_workbook( )->worksheet->for_name( 'Sheet1' ).
"Using selection patterns
"The XCO XLSX module works with selection patterns that define how the content
"in a worksheet is selected (i.e. whether everything or a restricted set is selected).
"Check the documentation for further information.
"The following selection pattern respects all values.
DATA(pattern_all) = xco_cp_xlsx_selection=>pattern_builder->simple_from_to( )->get_pattern( ).
"The following selection pattern restricts the content used. Here, column A is left
"out (starting from column B), and the first two rows are skipped (starting from row
"number 3).
DATA(pattern_restrict) = xco_cp_xlsx_selection=>pattern_builder->simple_from_to(
)->from_column( xco_cp_xlsx=>coordinate->for_alphabetic_value( 'B' )
)->from_row( xco_cp_xlsx=>coordinate->for_numeric_value( 3 )
)->get_pattern( ).
"--- Reading using row streams ---
"The examples reads into an internal table of a known structure.
"Declaring an internal table based on a local structure (representing
"the 'known structure')
TYPES: BEGIN OF carr_line_type,
carrid TYPE c LENGTH 3,
carrname TYPE c LENGTH 20,
currcode TYPE string,
url TYPE c LENGTH 255,
END OF carr_line_type,
carr_tab_type TYPE TABLE OF carr_line_type WITH EMPTY KEY.
DATA carr_tab TYPE carr_tab_type.
"Note that the content is written to a reference to an internal table
"with the write_to method.
worksheet1->select( pattern_all
)->row_stream(
)->operation->write_to( REF #( carr_tab )
)->execute( ).
"Retrieving the table lines to compare the values with the next
"example that uses a different selection pattern
DATA(lines_tab1) = lines( carr_tab ).
"Displaying the read result in the console
out->write( |Lines in carr_tab: { lines_tab1 }| ).
out->write( data = carr_tab name = `carr_tab` ).
out->write( |\n\n| ).
CLEAR carr_tab.
"Compare the content/output of the previous internal table and
"the following one. The CARRID field is not filled because of starting
"the selection in the second column. The first two entries of the previous
"internal table are not available in the other because of starting in
"the third row.
worksheet1->select( pattern_restrict
)->row_stream(
)->operation->write_to( REF #( carr_tab )
)->execute( ).
DATA(lines_tab2) = lines( carr_tab ).
out->write( |Lines in carr_tab: { lines_tab2 }| ).
out->write( data = carr_tab name = `carr_tab` ).
out->write( |\n\n| ).
"--- Reading via a cursor ---
"I.e. you specify the cursor position which represents the coordinate
"values of column and row. Once specified, you can access the content based
"on the cursor position in various directions using the MOVE* methods.
"The following internal table is created for output purposes and includes
"various pieces of cursor position information.
TYPES: BEGIN OF cursor_info,
string_value TYPE string,
cursor_position_column_alphab TYPE string,
cursor_position_column_num TYPE i,
cursor_position_row_alphab TYPE string,
cursor_position_row_num TYPE i,
END OF cursor_info.
DATA itab_cursor_info_move_down TYPE TABLE OF cursor_info WITH EMPTY KEY.
DATA itab_cursor_info_move_right TYPE TABLE OF cursor_info WITH EMPTY KEY.
DATA itab_cursor_info_move_left TYPE TABLE OF cursor_info WITH EMPTY KEY.
DATA itab_cursor_info_move_up TYPE TABLE OF cursor_info WITH EMPTY KEY.
DATA string_value TYPE string.
"Positioning the cursor (starting in column B, third row)
DATA(cursor) = worksheet1->cursor(
io_column = xco_cp_xlsx=>coordinate->for_alphabetic_value( 'B' )
io_row = xco_cp_xlsx=>coordinate->for_numeric_value( 3 )
).
"Retrieving column and row information and storing it in a structure for
"output purposes (to show where the cursor is positioned as specifed above)
DATA(cursor_set) = VALUE cursor_info(
cursor_position_column_alphab = cursor->position->column->get_alphabetic_value( )
cursor_position_column_num = cursor->position->column->get_numeric_value( )
cursor_position_row_alphab = cursor->position->row->get_alphabetic_value( )
cursor_position_row_num = cursor->position->row->get_numeric_value( )
).
"Getting the value
"Note: String value transformation is done in the example. Note the information
"in the documentation.
cursor->get_cell( )->get_value(
)->set_transformation( xco_cp_xlsx_read_access=>value_transformation->string_value
)->write_to( REF #( string_value ) ).
cursor_set-string_value = string_value.
out->write( |Cursor information| ).
out->write( |\n\n| ).
out->write( data = cursor_set name = `cursor_set` ).
out->write( |\n\n| ).
"Looping across the cells and retrieving individual cursor position information and
"the string values
"--- Moving down ---
WHILE cursor->has_cell( ) = abap_true AND cursor->get_cell( )->has_value( ) = abap_true.
DATA(cell_cnt) = cursor->get_cell( ).
"Storing column and row information in data objects
DATA(cursor_position_column_alphab) = cursor->position->column->get_alphabetic_value( ).
DATA(cursor_position_column_num) = cursor->position->column->get_numeric_value( ).
DATA(cursor_position_row_alphab) = cursor->position->row->get_alphabetic_value( ).
DATA(cursor_position_row_num) = cursor->position->row->get_numeric_value( ).
"Getting the content of the cell by applying a value transformation to the
"content
cell_cnt->get_value(
)->set_transformation( xco_cp_xlsx_read_access=>value_transformation->string_value
)->write_to( REF #( string_value ) ).
"Adding the column and row information and the string value to an internal table
"for output purposes
APPEND VALUE #(
string_value = string_value cursor_position_column_alphab = cursor_position_column_alphab
cursor_position_column_num = cursor_position_column_num
cursor_position_row_alphab = cursor_position_row_alphab
cursor_position_row_num = cursor_position_row_num ) TO itab_cursor_info_move_down.
"Moving the cursor down
TRY.
cursor->move_down( ).
CATCH cx_xco_runtime_exception.
EXIT.
ENDTRY.
ENDWHILE.
out->write( data = itab_cursor_info_move_down name = `itab_cursor_info_move_down` ).
out->write( |\n\n| ).
"--- Moving right ---
"Repositioning the cursor
cursor = worksheet1->cursor(
io_column = xco_cp_xlsx=>coordinate->for_alphabetic_value( 'B' )
io_row = xco_cp_xlsx=>coordinate->for_numeric_value( 3 ) ).
WHILE cursor->has_cell( ) = abap_true AND cursor->get_cell( )->has_value( ) = abap_true.
cell_cnt = cursor->get_cell( ).
cursor_position_column_alphab = cursor->position->column->get_alphabetic_value( ).
cursor_position_column_num = cursor->position->column->get_numeric_value( ).
cursor_position_row_alphab = cursor->position->row->get_alphabetic_value( ).
cursor_position_row_num = cursor->position->row->get_numeric_value( ).
cell_cnt->get_value(
)->set_transformation( xco_cp_xlsx_read_access=>value_transformation->string_value
)->write_to( REF #( string_value ) ).
APPEND VALUE #( string_value = string_value cursor_position_column_alphab = cursor_position_column_alphab
cursor_position_column_num = cursor_position_column_num
cursor_position_row_alphab = cursor_position_row_alphab
cursor_position_row_num = cursor_position_row_num ) TO itab_cursor_info_move_right.
"Moving the cursor right
TRY.
cursor->move_right( ).
CATCH cx_xco_runtime_exception.
EXIT.
ENDTRY.
ENDWHILE.
out->write( data = itab_cursor_info_move_right name = `itab_cursor_info_move_right` ).
out->write( |\n\n| ).
"--- Moving left ---
"Repositioning the cursor
cursor = worksheet1->cursor(
io_column = xco_cp_xlsx=>coordinate->for_alphabetic_value( 'B' )
io_row = xco_cp_xlsx=>coordinate->for_numeric_value( 3 ) ).
WHILE cursor->has_cell( ) = abap_true AND cursor->get_cell( )->has_value( ) = abap_true.
cell_cnt = cursor->get_cell( ).
cursor_position_column_alphab = cursor->position->column->get_alphabetic_value( ).
cursor_position_column_num = cursor->position->column->get_numeric_value( ).
cursor_position_row_alphab = cursor->position->row->get_alphabetic_value( ).
cursor_position_row_num = cursor->position->row->get_numeric_value( ).
cell_cnt->get_value(
)->set_transformation( xco_cp_xlsx_read_access=>value_transformation->string_value
)->write_to( REF #( string_value ) ).
APPEND VALUE #( string_value = string_value cursor_position_column_alphab = cursor_position_column_alphab
cursor_position_column_num = cursor_position_column_num
cursor_position_row_alphab = cursor_position_row_alphab
cursor_position_row_num = cursor_position_row_num ) TO itab_cursor_info_move_left.
"Moving the cursor left
TRY.
cursor->move_left( ).
CATCH cx_xco_runtime_exception.
EXIT.
ENDTRY.
ENDWHILE.
out->write( data = itab_cursor_info_move_left name = `itab_cursor_info_move_left` ).
out->write( |\n\n| ).
"--- Moving up ---
"Repositioning the cursor
cursor = worksheet1->cursor(
io_column = xco_cp_xlsx=>coordinate->for_alphabetic_value( 'B' )
io_row = xco_cp_xlsx=>coordinate->for_numeric_value( 3 ) ).
WHILE cursor->has_cell( ) = abap_true AND cursor->get_cell( )->has_value( ) = abap_true.
cell_cnt = cursor->get_cell( ).
cursor_position_column_alphab = cursor->position->column->get_alphabetic_value( ).
cursor_position_column_num = cursor->position->column->get_numeric_value( ).
cursor_position_row_alphab = cursor->position->row->get_alphabetic_value( ).
cursor_position_row_num = cursor->position->row->get_numeric_value( ).
cell_cnt->get_value(
)->set_transformation( xco_cp_xlsx_read_access=>value_transformation->string_value
)->write_to( REF #( string_value ) ).
APPEND VALUE #( string_value = string_value cursor_position_column_alphab = cursor_position_column_alphab
cursor_position_column_num = cursor_position_column_num
cursor_position_row_alphab = cursor_position_row_alphab
cursor_position_row_num = cursor_position_row_num ) TO itab_cursor_info_move_up.
"Moving the cursor up
TRY.
cursor->move_up( ).
CATCH cx_xco_runtime_exception.
EXIT.
ENDTRY.
ENDWHILE.
out->write( data = itab_cursor_info_move_up name = `itab_cursor_info_move_up` ).
out->write( |\n\n| ).
**********************************************************************
"------------------------ Write access to XLSX content ------------------------
"- The following example creates a new XLSX document.
"- Two worksheets are created.
"- New content is added (based on demo internal tables).
"- The existing XLSX content is replaced by the new content. An ABAP SQL UPDATE
" statement is included to update the file content. If you have implemented
" the SAP Fiori Elements and access the entry, you can download the new
" XLSX file to your local machine.
"---------------------------------- NOTE ----------------------------------
"---- Do note that this is just for demonstration purposes to quickly ----
"---- explore the new XLSX content (without considering RAP-related ----
"--- things and other database table fields such as the time stamps). ----
out->write( `-------------------- Write XLSX content --------------------` ).
out->write( |\n\n| ).
"Creating a new XLSX document
DATA(write_xlsx) = xco_cp_xlsx=>document->empty( )->write_access( ).
"Note that the name of the created worksheet is Sheet1
"Accessing the first worksheet via the position
DATA(ws1) = write_xlsx->get_workbook( )->worksheet->at_position( 1 ).
"Poviding XLSX content
"--- Writing data via a row stream ---
"In this case, the structure is statically known. The content of an internal table
"is used.
DATA(itab) = VALUE carr_tab_type(
( carrid = 'WX' carrname = 'Air WZ' currcode = 'GBP' url = 'some_url_wx' )
( carrid = 'XY' carrname = 'XY Airlines' currcode = 'EUR' url = 'some_url_xy' )
( carrid = 'YZ' carrname = 'YZ Airways' currcode = 'USD' url = 'some_url_yz' )
).
"As is the case with the read access, a pattern is used.
"The following pattern uses the entire content.
DATA(pattern_all4write) = xco_cp_xlsx_selection=>pattern_builder->simple_from_to( )->get_pattern( ).
"Writing the internal table lines to the worksheet using the write_from method
ws1->select( pattern_all4write
)->row_stream(
)->operation->write_from( REF #( itab )
)->execute( ).
"--- Writing data via a cursor ---
"To demonstrate this writing method, a new worksheet is created using the
"add_new_sheet method. A name is provided, too.
DATA(create_new_worksheet) = write_xlsx->get_workbook( )->add_new_sheet( `Sheet2` ).
"Accessing the second worksheet via the position
DATA(ws2) = write_xlsx->get_workbook( )->worksheet->at_position( 2 ).
"Checking if the new worksheet exists at position 2 using the exists method
DATA(ws2_pos_exists) = write_xlsx->get_workbook( )->worksheet->at_position( 2 )->exists( ).
IF ws2_pos_exists = abap_true.
out->write( `The newly created worksheet exists at position 2` ).
ELSE.
out->write( `The newly created worksheet does not exist at position 2` ).
ENDIF.
out->write( |\n\n| ).
"Another internal table to have different demo data in the two worksheets
DATA(itab2) = VALUE carr_tab_type(
( carrid = 'ZA' carrname = 'Air ZA' currcode = 'CAD' url = 'some_url_za' )
( carrid = 'YB' carrname = 'YB Airlines' currcode = 'JPY' url = 'some_url_yb' )
( carrid = 'XC' carrname = 'XC Airways' currcode = 'ZAR' url = 'some_url_xc' )
).
"Example implementation: Looping across the internal table to put individual
"component values in the worksheet
LOOP AT itab2 INTO DATA(wa).
DATA(tabix) = sy-tabix.
"Positioning the cursor
"The idea is to write all the content starting in the top left
"corner of the worksheet. You can imagine other positions when
"specifying actual parameters for io_column and io_row.
"More methods are available. See the documentation.
"Note: The cursor is repositioned with every loop pass here starting
"with the first column. The row value is represented by the table
"index (sy-tabix value), i.e. the second data set of the internal table
"available in the work area in the second loop pass table goes in the
"second row, and so on.
DATA(cursor4write) = ws2->cursor(
io_column = xco_cp_xlsx=>coordinate->for_alphabetic_value( 'A' )
io_row = xco_cp_xlsx=>coordinate->for_numeric_value( tabix ) ).
cursor4write->get_cell( )->value->write_from( wa-carrid ).
"Moving right to populate other columns
cursor4write->move_right( )->get_cell( )->value->write_from( wa-carrname ).
cursor4write->move_right( )->get_cell( )->value->write_from( wa-url ).
"Note: The example skips one component.
ENDLOOP.
"Once content has been provided, getting the file content (both worksheets of
"the example)
DATA(file_content) = write_xlsx->get_file_content( ).
"In this example, the uploaded XLSX content is replaced by the newly created
"XLSX content by just updating the file_content field. It is just for demonstration
"purposes as commented above.
"If you have created the SAP Fiori Elements preview app, you can download the XLSX file.
"To do so, access the app via the service binding as described. Find the entry with the
"provided ID (it is output in the console), and choose it. In the detail view of the app,
"you can choose the button next to the file content. It should download an XLSX file,
"now having the created content.
UPDATE ztdemo_abap_xlsx SET file_content = @file_content WHERE id = @xlsx-id.
IF sy-subrc = 0.
out->write( |The database table was updated. If implemented, check the file with id { xlsx-id }| ).
ELSE.
out->write( `The database table was not updated.` ).
ENDIF.
ENDMETHOD.
ENDCLASS. |
Class | Details/Code Snippet |
CL_ABAP_ZIP |
The following example creates a zip file and adds three txt files with sample content. Note that the example snippet for "Create zip file
DATA(zip) = NEW cl_abap_zip( ).
"Adding 3 files to a zip file
DO 3 TIMES.
DATA(some_content) = |{ sy-index }. Some text content|.
TRY.
DATA(conv_xstring) = cl_abap_conv_codepage=>create_out( codepage = `UTF-8` )->convert( some_content ).
CATCH cx_sy_conversion_codepage.
ENDTRY.
"Add xstring as file content to zip
zip->add( EXPORTING name = |file{ sy-index }.txt|
content = conv_xstring ).
ENDDO.
DATA(zipped_file) = zip->save( ). |
Class | Details/Code Snippet |
CL_ABAP_UNIT_ASSERT |
Provides methods to verify test expectations in ABAP Unit tests. For more information, see the ABAP Unit Tests cheat sheet. "Code in a test class
...
DATA(result) = 100.
...
cl_abap_unit_assert=>assert_equals(
act = result
exp = 100
msg = `The value does not match the expected result`
quit = if_abap_unit_constant=>quit-no ). |
CL_ABAP_TESTDOUBLE CL_OSQL_TEST_ENVIRONMENT CL_CDS_TEST_ENVIRONMENT CL_BOTD_TXBUFDBL_BO_TEST_ENV CL_BOTD_MOCKEMLAPI_BO_TEST_ENV |
|