Something about Dynamic ABAP
June 21, 2013 Leave a comment
It has been a while that I haven’t written anything new but it was due to making some ‘life-changing’ decisions recently and their impact on my ‘free-time’ activities.
First of all I decided to move to the lovely city of Dresden and start working in a company here, then I decided to get married and since my partner moved with me we had to find a new place to stay and equip it (it really takes some time to do that). OK, ok.. I admit I have been also searching for a wedding dress, invitation design, good wedding photographer and so it really takes some time.. 😉 I will now get to the point of the post in order not to annoy the male readers.
As the title says this time I will explain couple of concepts that are offered in ABAP that offer Real Time Type Services with a real-world problem.
Following is taken from help.sap.com:
The RTTS are implemented through a hierarchy of type classes that contain the methods for RTTC (Run Time Type Creation) and RTTI (Run Time Type Identification). With the help of these system classes it is possible to determine type information of existing instances and type names of the ABAP type system at runtime and to define new data types at runtime.
The properties of the types are represented by the attributes of type objects. For each type there is exactly one type object. The attributes of the type object contain information on the properties of the type. For each kind of type (elementary type, table, class, and so on), there is a type class with special attributes for special type properties. The class hierarchy of the type classes corresponds to the hierarchy of the type kinds in the ABAP type system.
In addition, type classes for complex types, references, classes, and interfaces have special methods for specifying references to partial types. With these methods, you can navigate to all partial types via a composite type.
Type objects can only be created through the methods of type classes. To get a reference to a type object of a type, you can use the static methods of the class CL_ABAP_TYPEDESCR or call methods of the special type classes.
Most important classes that every ABAPer has to know are:
CL_ABAP_TYPEDESCR
|
|–CL_ABAP_DATADESCR
| |
| |–CL_ABAP_ELEMDESCR
| |–CL_ABAP_REFDESCR
| |–CL_ABAP_COMPLEXDESCR
| |
| |–CL_ABAP_STRUCTDESCR
| |–CL_ABAP_TABLEDESCR
|
|–CL_ABAP_OBJECTDESCR
|
|–CL_ABAP_CLASSDESCR
|–CL_ABAP_INTFDESCR
One can not understand the meaning of Dynamic programming without an example so let’s see one possible scenario.
Let’s suppose you need to upload some data in a table, but you have to make the code flexible and useful for uploading data in any table, not just a pre-defined one. Usually we create an internal table, use GUI_UPLOAD and we are done. But the bad thing about this approach is that sometimes we need to reuse the code for another table but before we have to change the type of the internal table, save, activate, test the code, transfer it to productive system and these all steps take a lot of time. When you don’t really have it, it is better to find some smart fast solution 🙂
So let’s explain the code step by step:
1. Creating the variables that we will need:
REPORT zsax_upload_zmig_tables. TYPE-POOLS: abap, sydes. FIELD-SYMBOLS: TYPE table. FIELD-SYMBOLS: . FIELD-SYMBOLS: TYPE ANY. DATA: lv_tab TYPE c VALUE cl_abap_char_utilities=>horizontal_tab. DATA: lt_ftab TYPE lvc_t_fcat, wa_ftab TYPE LINE OF lvc_t_fcat, lt_ftab1 TYPE lvc_t_fcat WITH HEADER LINE, vals TYPE string, word TYPE string. DATA: it_file TYPE REF TO data, is_file TYPE REF TO data, dref TYPE REF TO data. DATA: serv_dir TYPE string VALUE '/usr/sap/SAX/SYS/global', filepath TYPE authb-filename, data_tab TYPE TABLE OF string, wa_line TYPE string, wa_tab TYPE string, itab TYPE TABLE OF string, comp TYPE string. DATA: gv_table_name TYPE string, gr_type_desc TYPE REF TO cl_abap_typedescr, gr_struct_desc TYPE REF TO cl_abap_structdescr, gr_table_desc TYPE REF TO cl_abap_tabledescr, gv_t TYPE c, gv_comp TYPE i, gr_table_ref TYPE REF TO data, gr_struc_ref TYPE REF TO data, descr_ref TYPE REF TO cl_abap_typedescr. DATA: gt_itab TYPE TABLE OF string, gt_split TYPE TABLE OF string, gv_str TYPE string, gv_stro TYPE string. DATA: td TYPE sydes_desc. FIELD-SYMBOLS: <table> TYPE ANY TABLE, <struct> TYPE ANY, <comp> TYPE ANY. PARAMETERS: l_file TYPE string DEFAULT 'D:\Zentraltabelle.txt'. PARAMETERS: table LIKE dd02l-tabname DEFAULT 'ZENTRAL'.
2. Upload data in a text table
CALL FUNCTION 'C13Z_UPLOAD' EXPORTING codepage = '1100' filename = l_file TABLES data_tab = data_tab . IF sy-subrc 0. write: 'Error!'. ENDIF.
3. Call to dynamically create the table
CALL FUNCTION 'LVC_FIELDCATALOG_MERGE' EXPORTING i_structure_name = table CHANGING ct_fieldcat = lt_ftab EXCEPTIONS OTHERS = 1. IF sy-subrc NE 0. WRITE: / 'Fehler bei Field catalog '. STOP. ENDIF. CALL METHOD cl_alv_table_create=>create_dynamic_table EXPORTING it_fieldcatalog = lt_ftab IMPORTING ep_table = it_file. CREATE DATA dref TYPE (table). ASSIGN dref->* TO . ASSIGN it_file->* TO . cl_abap_tabledescr=>describe_by_name( EXPORTING p_name = table RECEIVING p_descr_ref = gr_type_desc EXCEPTIONS type_not_found = 4 ). gr_struct_desc ?= gr_type_desc. gr_table_desc = cl_abap_tabledescr=>create( gr_struct_desc ). CREATE DATA gr_table_ref TYPE HANDLE gr_table_desc. CREATE DATA gr_struc_ref TYPE HANDLE gr_struct_desc. ASSIGN gr_table_ref->* TO <table>. ASSIGN gr_struc_ref->* TO . DESCRIBE FIELD TYPE gv_t COMPONENTS gv_comp.
3. Perform some parameter checks (if you happen to be dealing with Dates and crazy decimals)
LOOP AT data_tab INTO gv_str. CLEAR: gt_split. SPLIT gv_str AT lv_tab INTO TABLE gt_split. DO gv_comp TIMES. READ TABLE gt_split INTO gv_str INDEX sy-index. ASSIGN COMPONENT sy-index OF STRUCTURE TO . DESCRIBE FIELD INTO td. descr_ref = cl_abap_typedescr=>describe_by_data( ). CASE descr_ref->type_kind. " DATUM TYPE WHEN 'D'. CALL FUNCTION 'CONVERSION_EXIT_DATEX_INPUT' EXPORTING input = gv_str IMPORTING output = gv_stro. = gv_stro. WHEN 'P'. " DECIMAL TYPE CALL FUNCTION 'HRCM_STRING_TO_AMOUNT_CONVERT' EXPORTING string = gv_str decimal_separator = ',' thousands_separator = '.' * WAERS = ' ' IMPORTING betrg = * EXCEPTIONS * CONVERT_ERROR = 1 * OTHERS = 2 . WHEN 'F'. " DECIMAL TYPE CALL FUNCTION 'HRCM_STRING_TO_AMOUNT_CONVERT' EXPORTING string = gv_str decimal_separator = ',' thousands_separator = '.' * WAERS = ' ' IMPORTING betrg = * EXCEPTIONS * CONVERT_ERROR = 1 * OTHERS = 2 . WHEN 'T'. " TIME TYPE CALL FUNCTION 'CONVERSION_EXIT_TIMLO_INPUT' EXPORTING input = gv_str IMPORTING output = gv_stro. = gv_stro. WHEN OTHERS. " CHAR, NUMC... TYPE = gv_str. ENDCASE. CLEAR gv_str. ENDDO. INSERT INTO (table) VALUES . ENDLOOP.
4. Keep on ABAPing… 🙂
Next time I will write about dynamic creation of objects and dynamic calls of methods from objects.