La programmation dynamique en ABAP est un art particulier qui requiert acrobaties et équilibrismes…
Note : les field-symbols ont été en grande partie remplacés par les références (les fs sont la précédente génération). Une référence permet de faire tout ce que fait un fs et d'autres choses encore.
L'élément central de la programmation dynamique : les field-symbols.
/!\ Ne pas tenter de manipuler un field-symbol non assigné, sinon gare au GETWA_NOT_ASSIGNED
! /!\
FIELD-SYMBOLS : <et_plip> TYPE STANDARD TABLE, " Table <ls_plop> TYPE any, " Whatever <fs1>. "Whatever, short form...
ASSIGN ls_plop TO <ls_plop>. "Var ASSIGN (ls_plop) TO <fs1>. "Content of var. ie. if ls_foo-bar = '1234' ; ls_plop = 'ls_foo-bar' then <fs1> = '1234'. ASSIGN et_plip[] TO <et_plip>[]. "Table content
DATA wldv_val TYPE REF TO i. "Déclaration typée DATA wldv_val TYPE REF TO data. "Sans type DATA wldv_val TYPE REF TO cl_gui_alv_grid. "Type objet
GET REFERENCE OF wlv_val INTO wldv_val. "Référencement wldv_val->* = wlv_val2. "Déréférencement
Au delà de l'assignation de field-symbols depuis des sources instanciées et typées (même si le type peut ne pas être connu à l'avance), il faut aussi parfois pouvoir manipuler des données qui vont être crées lors de l'exécution et dont le type est inconnu à l'avance. Pour cela il va falloir recourir à des commandes particulières et à des fonctions qui vont puiser des informations directement auprès du kernel (autrefois des FM ALV, aujourd'hui des classes dédiées).
DATA: dy_line TYPE REF TO data. CREATE DATA dy_line LIKE LINE OF <et_plip>. ASSIGN dy_line->* TO <les_plop>.
Quelques classes utiles :
cl_abap_tabledescr
cl_abap_structdescr
cl_abap_typedescr
Exemple pratique : un MOVE-CORRESPONDING
dynamique (agnostique sur la structure d'entrée comme de sortie) !
DATA: ls_line TYPE abap_compdescr. REFRESH <et_plip>. LOOP AT lit_ausp ASSIGNING <ls_ausp>. " Get output structure components descr_ref ?= cl_abap_typedescr=>describe_by_data( <ls_ausp> ). LOOP AT descr_ref->components INTO ls_line. ASSIGN COMPONENT ls_line-name OF STRUCTURE <ls_ausp> TO <fs1>. IF sy-subrc NE 0. EXIT. ENDIF. ASSIGN COMPONENT ls_line-name OF STRUCTURE <ls_plop> TO <fs2>. IF sy-subrc = 0. <fs2> = <fs1>. ENDIF. ENDLOOP. APPEND <ls_plop> TO <et_plip>. ENDLOOP.
NB : il est évidemment possible d'enrichir ce code avec des fonctionnalités pour par exemple ne pas transporter les champs vides de la structure 1 vers la 2 ou encore faire des transcos au passage…
NB2 : Si la classe cl_abap_typedescr
n'est pas dispo, zieuter vers GET_COMPONENT_LIST
et GET_GLOBAL_SYMBOLS
.
METHOD create_data. DATA: lo_structdescr TYPE REF TO cl_abap_structdescr, lo_typedescr TYPE REF TO cl_abap_typedescr, lo_tabledescr TYPE REF TO cl_abap_tabledescr, lt_lvc_scol TYPE lvc_t_scol, lt_lvc_styl TYPE lvc_t_styl, lt_comp_all TYPE cl_abap_structdescr=>component_table. FIELD-SYMBOLS: <component> TYPE LINE OF abap_component_tab. APPEND INITIAL LINE TO lt_comp_all ASSIGNING <component>. <component>-type ?= cl_abap_datadescr=>describe_by_data( lt_lvc_styl ). <component>-name = lc_fieldname_t_styl. APPEND INITIAL LINE TO lt_comp_all ASSIGNING <component>. <component>-type ?= cl_abap_datadescr=>describe_by_data( lt_lvc_scol ). <component>-name = lc_fieldname_t_color. * create structure description lo_structdescr = cl_abap_structdescr=>create( lt_comp_all ). * create table description for structure lo_tabledescr = cl_abap_tabledescr=>create( p_line_type = lo_structdescr p_table_kind = cl_abap_tabledescr=>tablekind_std p_unique = abap_false ). * create data object CREATE DATA rr_dispodata TYPE HANDLE lo_tabledescr. ENDMETHOD.