10-22-2014 10:33 PM
I have an program built structure (not ddic). with several fields, all defined with ddic data elements.
TYPES:
BEGIN OF ty_selected,
material TYPE matnr,
matl_type TYPE mtart,
lab_office TYPE labor,
plant TYPE werks_d,
status TYPE mmsta,
END OF ty_selected.
DATA: gs_selected type ty_selected.
I want to retrieve the description text of the data elements that are in this structure. I just can't seen to get it. I figured it out for ddic structures but not program defined ones.
For ddic structures I am using class cl_abap_structdescr like this:
DATA: ref_struct TYPE REF TO cl_abap_structdescr,
ls_struct TYPE zmatl, " ddic type
lt_ddic_info TYPE ddfields,
w_head TYPE ty_return.
FIELD-SYMBOLS:
<ddic_info> TYPE LINE OF ddfields.
ref_struct ?= cl_abap_typedescr=>describe_by_data( ls_struct ).
lt_ddic_info = ref_struct->get_ddic_field_list( ).
LOOP AT lt_ddic_info ASSIGNING <ddic_info>.
MOVE <ddic_info>-fieldname TO w_head-fieldname.
MOVE <ddic_info>-fieldtext TO w_head-fieldtext.
APPEND w_head TO f_return.
ENDLOOP.
I figure there should be something similar I can do for program defined structures, but no joy.
Can anyone help me please?
Thanks
10-23-2014 10:13 AM
My 2 cents...
If we use the attribute CL_ABAP_STRUCTDESCR->COMPONENTS, then we'll have to code explicitly to get the RTTI for the individual components. On the other hand, if we use the method CL_ABAP_STRUCTDESCR->GET_COMPONENTS( ) then the framework does that implicitly.
DATA: lo_struct_descr TYPE REF TO cl_abap_structdescr,
lt_struct_fields TYPE cl_abap_structdescr=>component_table,
lwa_struct_field TYPE cl_abap_structdescr=>component,
lo_elem_descr TYPE REF TO cl_abap_elemdescr.
* Get RTTI object for the local structure
lo_struct_descr ?= cl_abap_typedescr=>describe_by_data( gs_selected ).
* Get the components of the structure
lt_struct_fields = lo_struct_descr->get_components( ).
LOOP AT lt_struct_fields INTO lwa_struct_field.
* Get the RTTI for the component
lo_elem_descr ?= lwa_struct_field-type.
cl_demo_output=>write_text(
|{ lwa_struct_field-name },| &&
|Text: { lo_elem_descr->get_ddic_field( )-scrtext_l } \n|
).
ENDLOOP.
cl_demo_output=>display( ).
For ABAP 740 lovers, here's the shorter version
LOOP AT CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( gs_selected ) )->get_components( )
INTO DATA(wa_structure_field).
cl_demo_output=>write_text( |{ to_mixed( wa_structure_field-name ) } \t| &&
|{ CAST cl_abap_elemdescr( wa_structure_field-type )->get_ddic_field( )-scrtext_l } \n|
).
ENDLOOP.
cl_demo_output=>display( ).
BR,
Suhas
Message was edited by: Suhas Saha
10-23-2014 12:33 AM
Hi Larry,
Yes, there is a way. You need to read each component individually (class cl_abap_elemdescr ). See code below:
TYPES:
BEGIN OF ty_selected,
material TYPE matnr,
matl_type TYPE mtart,
lab_office TYPE labor,
plant TYPE werks_d,
status TYPE mmsta,
END OF ty_selected.
DATA: ref_struct TYPE REF TO cl_abap_structdescr,
ref_element TYPE REF TO cl_abap_elemdescr,
ddic TYPE dfies,
component TYPE abap_compdescr.
ref_struct ?= cl_abap_typedescr=>describe_by_name( 'TY_SELECTED' ).
LOOP AT ref_struct->components INTO component..
ref_element ?= cl_abap_typedescr=>describe_by_name( 'TY_SELECTED-' && component-name ).
ddic = ref_element->get_ddic_field( ).
WRITE: / ddic-scrtext_m.
IF sy-subrc <> 0.
*handle exception
ENDIF.
ENDLOOP.
Regards,
Custodio
10-23-2014 5:48 AM
Hi,
Very similar to version but using by describe_by_data all the way .
*----------------------------------------------------------------------*
TYPES: BEGIN OF tp_level_1 .
INCLUDE TYPE scarr AS scarr RENAMING WITH SUFFIX _scarr .
INCLUDE TYPE spfli AS spfli RENAMING WITH SUFFIX _spfli .
TYPES: END OF tp_level_1 .
*----------------------------------------------------------------------*
START-OF-SELECTION .
PERFORM test_01 .
*----------------------------------------------------------------------*
FORM test_01 .
DATA: st_level_1 TYPE tp_level_1 .
DATA: ob_abap_structdescr TYPE REF TO cl_abap_structdescr .
ob_abap_structdescr ?= cl_abap_typedescr=>describe_by_data( st_level_1 ) .
DATA: st_components LIKE LINE OF ob_abap_structdescr->components .
FIELD-SYMBOLS: <component> TYPE ANY .
DATA: ob_abap_elemdescr TYPE REF TO cl_abap_elemdescr .
DATA: st_dfies TYPE dfies .
LOOP AT ob_abap_structdescr->components INTO st_components .
ASSIGN COMPONENT st_components-name OF STRUCTURE st_level_1 TO <component> .
ob_abap_elemdescr ?= cl_abap_typedescr=>describe_by_data( <component> ) .
st_dfies = ob_abap_elemdescr->get_ddic_field( ) .
WRITE: / st_components-name , st_dfies-fieldtext .
ENDLOOP .
ENDFORM . "test_01
*----------------------------------------------------------------------*
Regards.
10-23-2014 10:13 AM
My 2 cents...
If we use the attribute CL_ABAP_STRUCTDESCR->COMPONENTS, then we'll have to code explicitly to get the RTTI for the individual components. On the other hand, if we use the method CL_ABAP_STRUCTDESCR->GET_COMPONENTS( ) then the framework does that implicitly.
DATA: lo_struct_descr TYPE REF TO cl_abap_structdescr,
lt_struct_fields TYPE cl_abap_structdescr=>component_table,
lwa_struct_field TYPE cl_abap_structdescr=>component,
lo_elem_descr TYPE REF TO cl_abap_elemdescr.
* Get RTTI object for the local structure
lo_struct_descr ?= cl_abap_typedescr=>describe_by_data( gs_selected ).
* Get the components of the structure
lt_struct_fields = lo_struct_descr->get_components( ).
LOOP AT lt_struct_fields INTO lwa_struct_field.
* Get the RTTI for the component
lo_elem_descr ?= lwa_struct_field-type.
cl_demo_output=>write_text(
|{ lwa_struct_field-name },| &&
|Text: { lo_elem_descr->get_ddic_field( )-scrtext_l } \n|
).
ENDLOOP.
cl_demo_output=>display( ).
For ABAP 740 lovers, here's the shorter version
LOOP AT CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( gs_selected ) )->get_components( )
INTO DATA(wa_structure_field).
cl_demo_output=>write_text( |{ to_mixed( wa_structure_field-name ) } \t| &&
|{ CAST cl_abap_elemdescr( wa_structure_field-type )->get_ddic_field( )-scrtext_l } \n|
).
ENDLOOP.
cl_demo_output=>display( ).
BR,
Suhas
Message was edited by: Suhas Saha
10-23-2014 11:05 AM
I'm loving Eitan's and Suhas' answers (both better than mine). I reckon this is what happens when the question is good.
To be honest I thought about doing both, but implemented mine first and got lazy
From now on I'll follow Suha's example and will always post ABAP 740 replies as well.
Cheers,
Custodio
10-23-2014 11:16 AM
Hello Custodio,
Our development system is still on ABAP 731, so i don't get to use the new version of ABAP regularly
The sandbox had been upgraded to 740 last December & i write all the demo programs there in 740 using AiE
BR,
Suhas
10-23-2014 11:06 PM
10-26-2014 8:32 AM
10-27-2014 1:10 AM
Yep, would need to work with get_components( ) and apply some fancy recursive logic here I reckon.
10-27-2014 5:48 AM
Hi,
You are right.
Actually I did a test (with recursion) but I do not like it since you have to manage the "RENAMING WITH SUFFIX" manually .
And what can I say I am lazy and I love kiss(http://en.wikipedia.org/wiki/KISS_principle) .
Code:
*----------------------------------------------------------------------*
CLASS cl_components DEFINITION .
PUBLIC SECTION.
METHODS get_components
IMPORTING st_abap_componentdescr TYPE abap_componentdescr
CHANGING it_ddfields TYPE ddfields .
ENDCLASS . "cl_event_receiver DEFINITION
*----------------------------------------------------------------------*
CLASS cl_components IMPLEMENTATION.
*----------------------------------------------------------------------*
METHOD get_components .
DATA: it_component_table TYPE cl_abap_structdescr=>component_table .
FIELD-SYMBOLS: <st_component_table> LIKE LINE OF it_component_table .
DATA: ob_abap_structdescr TYPE REF TO cl_abap_structdescr .
ob_abap_structdescr ?= st_abap_componentdescr-type .
it_component_table = ob_abap_structdescr->get_components( ) .
DATA: st_ddfields LIKE LINE OF it_ddfields .
DATA: ob_abap_elemdescr TYPE REF TO cl_abap_elemdescr .
DATA: is_ddic TYPE abap_bool .
LOOP AT it_component_table ASSIGNING <st_component_table> .
CASE <st_component_table>-type->kind .
WHEN cl_abap_typedescr=>kind_struct .
me->get_components(
EXPORTING
st_abap_componentdescr = <st_component_table>
CHANGING
it_ddfields = it_ddfields ) .
WHEN cl_abap_typedescr=>kind_elem .
CLEAR st_ddfields .
ob_abap_elemdescr ?= <st_component_table>-type .
is_ddic = ob_abap_elemdescr->is_ddic_type( ) .
IF is_ddic EQ abap_true .
st_ddfields = ob_abap_elemdescr->get_ddic_field( ) .
ELSE .
st_ddfields-intlen = <st_component_table>-type->length .
st_ddfields-decimals = <st_component_table>-type->decimals .
st_ddfields-inttype = <st_component_table>-type->type_kind .
ENDIF .
CONCATENATE <st_component_table>-name st_abap_componentdescr-suffix
INTO st_ddfields-fieldname .
APPEND st_ddfields TO it_ddfields .
WHEN OTHERS.
CONTINUE .
ENDCASE.
ENDLOOP .
ENDMETHOD . "get_components
ENDCLASS . "cl_components IMPLEMENTATION
*----------------------------------------------------------------------*
*----------------------------------------------------------------------*
TYPES: BEGIN OF tp_level_1 .
INCLUDE TYPE scarr AS scarr RENAMING WITH SUFFIX _scarr .
TYPES: flag TYPE boolean .
TYPES: c_field TYPE c LENGTH 1 .
TYPES: n_field TYPE n LENGTH 1 .
TYPES: s_strng TYPE string .
TYPES: it_return TYPE bapirettab .
TYPES: ob_gui_alv_grid TYPE REF TO cl_gui_alv_grid .
TYPES: END OF tp_level_1 .
*----------------------------------------------------------------------*
*----------------------------------------------------------------------*
FORM test_06 .
DATA: st_level_1 TYPE tp_level_1 .
DATA: st_abap_componentdescr TYPE abap_componentdescr .
st_abap_componentdescr-type ?= cl_abap_typedescr=>describe_by_data( st_level_1 ) .
DATA: ob_components TYPE REF TO cl_components .
DATA: it_ddfields TYPE ddfields .
CREATE OBJECT ob_components .
ob_components->get_components(
EXPORTING st_abap_componentdescr = st_abap_componentdescr
CHANGING it_ddfields = it_ddfields ) .
BREAK-POINT .
ENDFORM . "test_06
*----------------------------------------------------------------------*
Regards.
Eitan.
10-27-2014 3:08 PM
I would say horses-for-courses, use the method that suits your requirement.
04-07-2016 6:51 AM
Hi Suhas,
Thanks for posting your solution. I used your solution to help check that the data uploaded via file was of the correct field length.
DATA: ls_message TYPE ty_messages,
lx_exception TYPE REF TO cx_root,
lt_struct_fields TYPE cl_abap_structdescr=>component_table,
ls_struct_comps TYPE cl_abap_structdescr=>component,
lo_strucdescr TYPE REF TO cl_abap_structdescr,
lo_elemdescr TYPE REF TO cl_abap_elemdescr,
lv_length TYPE string,
lv_index TYPE i,
ls_data LIKE LINE OF data.
TRY.
* "dynamically check data is not longer than allowed field length
lo_strucdescr ?= cl_abap_typedescr=>describe_by_data( ls_data ).
lt_struct_fields = lo_strucdescr->get_components( ).
DO lines( lo_strucdescr->components ) TIMES.
lv_index = sy-index.
ASSIGN COMPONENT lv_index OF STRUCTURE is_raw_data TO FIELD-SYMBOL(<fs>).
READ TABLE lt_struct_fields INDEX lv_index INTO ls_struct_comps.
lo_elemdescr ?= ls_struct_comps-type.
CHECK lo_elemdescr IS BOUND.
IF strlen( <fs> ) > lo_elemdescr->output_length.
rv_error = 'X'.
lv_length = lo_elemdescr->output_length.
ls_message-type = 'E'.
CONCATENATE 'Row' iv_row ls_struct_comps-name 'is longer than allowed length of' lv_length INTO ls_message-message SEPARATED BY space.
APPEND ls_message TO messages.
CLEAR: lv_length.
ENDIF.
ENDDO.
ENDTRY.
cheers
Julian
10-23-2014 2:43 PM
Thanks everyone! This is exactly what I was looking for. I wish I could have given everyone the correct answer points, but it only allows for one. I have already implemented Syhas' code and it is working great! Thanks again.
I never can remember how to add a code block to my posts. Tell me again how that is done.
10-23-2014 11:11 PM
Hi Larry,
Use the "Advanced editor" then follow this:
Cheers,
Custodio
10-24-2014 12:55 AM
Thanks!
But I probably will forget by the next time
I post a question!
Maybe I should spend a little more time on here and try to answer a few questions myself.
And I won't forget how to do it!
10-24-2014 8:04 AM
Hi,
This is a very good idea .
SCN is a great place to remember stuff .
You might search for something and than you find your OWN answers....
Regards .
10-24-2014 3:21 PM
I always search for the answer first. That is why I don't post a question very often. I find the answer most of the time without posting.