Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

cl_abap_structdescr finding data element descriptions of program defined structure

Former Member

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

1 ACCEPTED SOLUTION

SuhaSaha
Advisor
Advisor

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

16 REPLIES 16

custodio_deoliveira
Active Contributor
0 Kudos

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

rosenberg_eitan
Active Contributor
0 Kudos

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.

SuhaSaha
Advisor
Advisor

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

0 Kudos

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

0 Kudos

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

0 Kudos

^same scenario here

0 Kudos

Hi

It seems that you get two different answers if you have a type like this:

cl_abap_structdescr->components :

ob_abap_structdescr->get_components :

Regards.

0 Kudos

Yep, would need to work with get_components( ) and apply some fancy recursive logic here I reckon.

0 Kudos

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.

0 Kudos

I would say horses-for-courses, use the method that suits your requirement.

0 Kudos

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

Former Member
0 Kudos

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.

0 Kudos

Hi Larry,

Use the "Advanced editor" then follow this:

Cheers,

Custodio

0 Kudos

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!

0 Kudos

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 .

0 Kudos

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.