Dynamic Programming & RTTS
RTTS = RTTI (Runtime Type Identification: describe types) + RTTC (Runtime Type Creation: build new types).
25.1 Runtime Type Services (RTTS)
RTTS = RTTI (Runtime Type Identification: describe types) + RTTC (Runtime Type Creation: build new types). Classes start with CL_ABAP_*DESCR:
CL_ABAP_TYPEDESCR
├── CL_ABAP_DATADESCR
│ ├── CL_ABAP_ELEMDESCR
│ ├── CL_ABAP_COMPLEXDESCR
│ │ ├── CL_ABAP_STRUCTDESCR
│ │ └── CL_ABAP_TABLEDESCR
│ └── CL_ABAP_REFDESCR
└── CL_ABAP_OBJECTDESCR
├── CL_ABAP_CLASSDESCR
└── CL_ABAP_INTFDESCR25.2 RTTI: inspecting types
DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( ls_order ) ).
LOOP AT lo_struct->get_components( ) INTO DATA(ls_comp).
out->write( |{ ls_comp-name }: { ls_comp-type->type_kind } { ls_comp-type->length }| ).
ENDLOOP.
DATA(lo_type) = cl_abap_typedescr=>describe_by_name( 'SFLIGHT' ).
DATA(lo_elem) = CAST cl_abap_elemdescr( cl_abap_typedescr=>describe_by_data( lv_amount ) ).
DATA(lt_ddic) = lo_elem->get_ddic_field( ). " DDIC info if typed with data element
DATA(lv_class) = cl_abap_classdescr=>get_class_name( lo_obj ).25.3 RTTC: creating types at runtime
DATA(lt_components) = VALUE cl_abap_structdescr=>component_table(
( name = 'ID' type = cl_abap_elemdescr=>get_i( ) )
( name = 'NAME' type = cl_abap_elemdescr=>get_string( ) )
( name = 'AMOUNT' type = cl_abap_elemdescr=>get_p( p_length = 8 p_decimals = 2 ) ) ).
DATA(lo_new_struct) = cl_abap_structdescr=>get( lt_components ).
DATA(lo_new_table) = cl_abap_tabledescr=>get( p_line_type = lo_new_struct ).
DATA lr_table TYPE REF TO data.
CREATE DATA lr_table TYPE HANDLE lo_new_table.
ASSIGN lr_table->* TO FIELD-SYMBOL(<lt_dynamic>).25.4 Generic table display from any DB table
(Production code must also do an authorization check on table access — e.g. S_TABU_NAM / S_TABU_DIS.)
PARAMETERS p_tab TYPE tabname DEFAULT 'SCARR'.
START-OF-SELECTION.
DATA lr_data TYPE REF TO data.
TRY.
cl_abap_dyn_prg=>check_table_name_str( val = p_tab packages = '' ).
CATCH cx_abap_not_a_table cx_abap_not_in_package.
MESSAGE 'Invalid table' TYPE 'E'.
ENDTRY.
CREATE DATA lr_data TYPE STANDARD TABLE OF (p_tab).
ASSIGN lr_data->* TO FIELD-SYMBOL(<lt_data>).
SELECT * FROM (p_tab) INTO TABLE @<lt_data> UP TO 100 ROWS.
cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_alv) CHANGING t_table = <lt_data> ).
lo_alv->display( ).25.5 Dynamic calls
Dynamic calls bypass compile-time checks — catch CX_SY_DYN_CALL_ERROR (subclasses like CX_SY_DYN_CALL_ILLEGAL_METHOD) and CX_SY_CREATE_OBJECT_ERROR.
" Dynamic method call
DATA(lv_class) = `ZCL_ORDER_SERVICE`.
DATA(lv_method) = `GET_OPEN_ORDERS`.
DATA lo_obj TYPE REF TO object.
CREATE OBJECT lo_obj TYPE (lv_class).
DATA(lt_params) = VALUE abap_parmbind_tab(
( name = 'IV_CUSTOMER' kind = cl_abap_objectdescr=>exporting value = REF #( lv_customer ) )
( name = 'RT_ORDERS' kind = cl_abap_objectdescr=>receiving value = REF #( lt_result ) ) ).
CALL METHOD lo_obj->(lv_method) PARAMETER-TABLE lt_params.
" Static method dynamically
CALL METHOD (lv_class)=>(lv_static_method).
" Dynamic function call
CALL FUNCTION lv_fm_name EXPORTING iv_x = 1 EXCEPTIONS OTHERS = 1.
" Dynamic SUBMIT / PERFORM
SUBMIT (lv_report) AND RETURN.
PERFORM (lv_form) IN PROGRAM (lv_program) IF FOUND.25.6 Dynamic SQL and generic code
Dynamic SELECT clauses (§15.7), dynamic WHERE/ORDER BY, dynamic sort (SORT itab BY (lv_field)), dynamic READ TABLE … WITH KEY (lv_field) = value, and dynamic LOOP … WHERE (lv_cond) (7.02+) all accept tokens at runtime.
25.7 Program generation (avoid)
GENERATE SUBROUTINE POOL and INSERT REPORT create code at runtime. They're security-sensitive, unavailable in ABAP Cloud, and almost always replaceable by RTTS and dynamic calls.