16.3    Runtime Type Services

ABAP Runtime Type Services (RTTS) is an object-oriented framework that consists of the following elements:

The RTTS framework implements a hierarchy of classes, as shown in Figure 16.4, via which we can determine the type information of data objects and define new data types at runtime. The instances of these type classes are known as type objects.

For each ABAP type, such as elementary types, reference types, complex types (structures and tables), and so on, there exists a type class.

Type Class Hierarchy

Figure 16.4    Type Class Hierarchy

For each ABAP type, there can exist exactly one type object in the program, and we can create new type objects for new types. The type objects contain attributes that describe the type. The class documentation provides information on each type class.

In the following subsections, we’ll discuss RTTI and RTTC in greater detail.

16.3.1    Runtime Type Information

Often, you’ll need to dynamically determine the type information of an object. For example, before using a generically typed parameter of a procedure or a generically typed anonymous data object in an arithmetic operation, you may want to check its type, length, and number of decimal places. In such cases, you can use type objects to identify the type information of a data object.

Type objects are created using the methods of the type class. The attributes of the type object contain the type information. Listing 16.25 shows example code to identify the type information.

REPORT ZDEMO_EXAMPLES.
TYPES: ty_type TYPE p DECIMALS 2.
DATA: v_data TYPE ty_type,
r_typedescr TYPE REF TO cl_abap_typedescr.
START-OF-SELECTION.
r_typedescr = cl_abap_typedescr=>describe_by_data( v_data ).

WRITE: / 'Kind:', r_typedescr->type_kind.
WRITE: / 'Length:', r_typedescr->length.
WRITE: / 'Decimals:', r_typedescr->decimals.

Listing 16.25    Querying Type Information

In Listing 16.25, we’ve defined a R_TYPEDESCR type object as an instance of the type class CL_ABAP_TYPEDESCR. The type object is instantiated when the DESCRIBE_BY_DATA static method of the type class is called. To this static method, we’re passing the data object for which the type information is required.

Once the type object is instantiated with the type information, we can access its attributes to determine the type information of the data object. The type object also contains constants that can be used in an IF or CASE structure to compare the TYPE_KIND attribute.

16.3.2    Runtime Type Creation

As discussed in the previous section, type objects are created using RTTI methods of RTTS; these type objects can be used to create new types using the RTTC methods of RTTS. The RTTC methods allow you to dynamically create data types that can be used to define data objects dynamically.

For example, say you want to dynamically create a structure on the fly and use it in a SELECT statement. You’ll only know the fields of the structure at runtime. In such a situation, you use the RTTC methods to define a data type and use to dynamically create the data object. The GET factory method of the CL_ABAP_STRUCTDESCR, CL_ABAP_TABLEDESCR, and CL_ABAP_REFDESCR classes allows you to create a type object.

The required information to create the type object is passed to the factory method of these classes. For example, the component details are passed to the factory method of the CL_ABAP_STRUCTDESCR class to create the type object for structure. Similarly, the structure type object is passed to the factory method of the CL_ABAP_TABLEDESCR class to create the table type object. Listing 16.26 shows how the RTTC methods can be used to dynamically define data types and create data objects using these types.

In Listing 16.26, we’ve defined two selection screen fields to take the table name and the WHERE clause as input. The program logic is built to display data from any table given as the input.

To achieve this, in the GET_TABLE subroutine, we’re dynamically identifying the type information of the given structure to get its components. We’re building an internal table on the fly using these components and writing a dynamic SELECT statement to get the data from the requested table. Finally, we’re displaying the output using ALV in the DISPLAY_TABLE subroutine.

PARAMETERS: p_table TYPE string,
p_where TYPE string.

DATA: r_typedescr TYPE REF TO cl_abap_typedescr,
r_structdescr TYPE REF TO cl_abap_structdescr,
r_tabledescr TYPE REF TO cl_abap_tabledescr,
r_table TYPE REF TO data,
components TYPE cl_abap_structdescr=>component_table,
component LIKE LINE OF components,
ro_alv TYPE REF TO cl_salv_table.

FIELD-SYMBOLS : <table> TYPE ANY TABLE.
START-OF-SELECTION.
PERFORM get_table.
PERFORM display_table.
*&------------------------------------------------------------*
*& Form GET_TABLE
*&------------------------------------------------------------*
* text
*-------------------------------------------------------------*
FORM get_table .
r_typedescr = cl_abap_typedescr=>describe_by_name( p_table ).
TRY.
r_structdescr ?= r_typedescr.
CATCH cx_sy_move_cast_error.
ENDTRY.
components = r_structdescr->get_components( ).
TRY.
r_structdescr = cl_abap_structdescr=>get( components ).
r_tabledescr = cl_abap_tabledescr=>get( r_structdescr ).
CATCH cx_sy_struct_creation.
CATCH cx_sy_table_creation .
ENDTRY.
TRY.
CREATE DATA r_table TYPE HANDLE r_tabledescr.
ASSIGN r_table->* TO <table>.
CATCH cx_sy_create_data_error.
ENDTRY.
TRY.
SELECT *
FROM (p_table)
INTO CORRESPONDING FIELDS OF TABLE <table> WHERE (p_where).
CATCH cx_sy_sql_error.
ENDTRY.
ENDFORM.
*&------------------------------------------------------------*
*& Form DISPLAY_TABLE
*&------------------------------------------------------------*
* text
*-------------------------------------------------------------*
FORM display_table .
TRY.
CALL METHOD cl_salv_table=>factory
IMPORTING
r_salv_table = ro_alv
CHANGING
t_table = <table>.
CATCH cx_salv_msg.
ENDTRY.
ro_alv->display( ).
ENDFORM.

Listing 16.26    Dynamic Type Creation

In the GET_TABLE subroutine of Listing 16.26, we’re first creating the R_TYPEDESCR type object based on the table name entered on the selection screen. We’re downcasting the R_TYPEDESCR type object to R_STRUCTDESCR. The R_STRUCTDESCR type object is an instance of the CL_ABAP_STRUCTDESCR class that contains the RTTC methods to create new type objects.

We’re calling the GET_COMPONENTS method to get the components of the structure. Using this information, we call the GET factory method of the CL_ABAP_STRUCTDESCR class to create the structure type object. We pass this structure type object to the GET factory method of the CL_ABAP_TABLEDESCR class to create the table type object.

Once we have the table type object, we use the TYPE HANDLE addition with the CREATE statement to instantiate the data reference with the type object. This will create the R_TABLE data reference, the type definition of which is defined in the R_TABLEDESCR type object.

Although the TYPE or LIKE addition allows you to specify a data type or data object, respectively, the TYPE HANDLE addition with the CREATE DATA statement allows you to specify a type object.

After the internal table is defined dynamically, we use it in the SELECT statement to query the given database table and subsequently display the output. As you can see, we’re handling the errors at each step; error handling is vital to dynamic programming.

If the user completes the fields as shown in Figure 16.5, the code in Listing 16.26 will generate the output as shown in Figure 16.6. We can enhance the code further to select only specific fields of the table and create the structure with only specific fields.

Selection Screen for Data Browser

Figure 16.5    Selection Screen for Data Browser

Data Browser Output

Figure 16.6    Data Browser Output

In this section, we looked at both RTTI and RTTC. In the next section, we’ll look at using dynamic tokens.