Something about Dynamic ABAP

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=&gt;create_dynamic_table
  EXPORTING
    it_fieldcatalog = lt_ftab
  IMPORTING
    ep_table        = it_file.

CREATE DATA dref TYPE (table).
ASSIGN dref-&gt;* TO .

ASSIGN it_file-&gt;* TO .

cl_abap_tabledescr=&gt;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=&gt;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-&gt;* TO <table>.
ASSIGN gr_struc_ref-&gt;* 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=&gt;describe_by_data(  ).

    CASE descr_ref-&gt;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.