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: 

Exception handling from class CL_ABAP_ELEMDESCR of method DESCRIBE_BY_NAME

rmnachi_kx
Explorer

Dears,

I'm trying to create a program which reads Z program lines and find the appropriate domain attributes of the data declared in the program. For this, I'm using class CL_ABAP_ELEMDESCR. When I provide any invalid input, this class is throwing TYPE_NOT_FOUND exception and system is running into a dump. its reasonable as I'm not catching this exception. So when I try to catch the exception using below shorter way, system is not allowing with error TYPE_NOT_FOUND is unknown. CATCH CX_ROOT is not working.

DATA: cl_workarea      TYPE REF TO cl_abap_elemdescr.
DATA: dd_dfies         TYPE dfies,
TRY.
    cl_workarea ?= cl_abap_elemdescr=>describe_by_name( 'KATNR'  ).
*CATCH type_not_found.
CATCH cx_root.
ENDTRY.

dd_dfies = cl_workarea->get_ddic_field( ). 

So, I'm going with below work around. I understand why I'm not able to catch TYPE_NOT_FOUND from describe_by_name method using TRY and CATCH. But is there a way to catch this and do in shorter version ? I tried going through below link, but that is not working for me.

https://archive.sap.com/discussions/thread/1694699

I'm in ECC6 EhP4.

Thanks for responses,
Nachi.RM

DATA: cl_workarea     TYPE REF TO cl_abap_elemdescr.
DATA: cl_wwarea       TYPE REF TO cl_abap_typedescr.

CALL METHOD cl_abap_elemdescr=>describe_by_name
  EXPORTING
    p_name         = 'MATNR'
  receiving
    p_descr_ref    = cl_wwarea
  EXCEPTIONS
    type_not_found = 1
    others         = 2.

cl_workarea ?= cl_wwarea.
dd_dfies = cl_workarea->get_ddic_field( ).
1 ACCEPTED SOLUTION

fabianlupa
Contributor

Not sure what you expect. If you want describe_by_name to use the newer OO exceptions you would have to write your own utility method to encapsulate the method call and exception handling. Put it in a utility class or you could even subclass cl_abap_typedescr and add describe_by_name_2 (or even add the method using an enhancement). Utility class would be the cleanest option.

CLASS zcl_rtti_utilities DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE.

  PUBLIC SECTION.
    CLASS-METHODS:
      "! Get a typedescriptor instance by type name
      "! @parameter ig_name | Type name
      "! @parameter ro_descr | Descriptor
      "! @raising zcx_type_not_found | Type not found
      describe_by_name IMPORTING ig_name         TYPE any
                       RETURNING VALUE(ro_descr) TYPE REF TO cl_abap_typedescr
                       RAISING   zcx_type_not_found.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_rtti_utilities IMPLEMENTATION.
  METHOD describe_by_name.
    cl_abap_typedescr=>describe_by_name(
      EXPORTING
        p_name         = ig_name
      RECEIVING
        p_descr_ref    = ro_descr
      EXCEPTIONS
        type_not_found = 1
        OTHERS         = 2
    ).
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_type_not_found
        MESSAGE ID sy-msgid
        TYPE sy-msgty
        NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

TRY.
    DATA(lo_descr) = CAST cl_abap_structdescr( zcl_rtti_utilities=>describe_by_name( 'T000' ) ).
  CATCH zcx_type_not_found cx_sy_move_cast_error.
    ASSERT 1 = 2.
ENDTRY.

If you want a cleaner way to call the standard API maybe this helps?

cl_abap_typedescr=>describe_by_name( EXPORTING p_name          = 'T000'
                                     RECEIVING p_descr_ref     = DATA(lo_descr)
                                     EXCEPTIONS type_not_found = 1 ).
DATA(lo_struct_descr) = CAST cl_abap_structdescr(
                          COND #( WHEN sy-subrc = 0 THEN lo_descr
                                  ELSE THROW zcx_type_not_found(
                                               MESSAGE ID sy-msgid
                                               TYPE sy-msgty
                                               NUMBER sy-msgno
                                               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
                                             ) )
                        ).

I personally most of the time don't catch type_not_found at all. Then you can use the functional method call in expressions etc. In my use cases if type_not_found is raised then this indicates a programming error (because I probably got the type name using RTTI anyways beforehand). And therefore a dump is just as fine as an assertion error.

https://blogs.sap.com/2015/11/12/abap-news-for-release-750-converting-messages-into-exceptions/

https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abenconditional_ex...

https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abenif_t100_dyn_ms...

7 REPLIES 7

Sandra_Rossi
Active Contributor

Please read the ABAP documentation carefully.

TYPE_NOT_FOUND is a classic exception. So, TRY CATCH cannot handle it.

This classic exception is to be handled via CALL METHOD ... EXCEPTIONS type_not_found = 1 and SY-SUBRC will take the value 1 if TYPE_NOT_FOUND occurs.

If you look at my Question, I have already mentioned that, I understand why I'm not able to catch TYPE_NOT_FOUND from describe_by_name method using TRY and CATCH.

My only question was, is there a simpler way to catch it. If you look at the below code part, I have used CALL FUNCTION to catch the exception.

Thanks for your response....

fabianlupa
Contributor

Not sure what you expect. If you want describe_by_name to use the newer OO exceptions you would have to write your own utility method to encapsulate the method call and exception handling. Put it in a utility class or you could even subclass cl_abap_typedescr and add describe_by_name_2 (or even add the method using an enhancement). Utility class would be the cleanest option.

CLASS zcl_rtti_utilities DEFINITION
  PUBLIC
  FINAL
  CREATE PRIVATE.

  PUBLIC SECTION.
    CLASS-METHODS:
      "! Get a typedescriptor instance by type name
      "! @parameter ig_name | Type name
      "! @parameter ro_descr | Descriptor
      "! @raising zcx_type_not_found | Type not found
      describe_by_name IMPORTING ig_name         TYPE any
                       RETURNING VALUE(ro_descr) TYPE REF TO cl_abap_typedescr
                       RAISING   zcx_type_not_found.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_rtti_utilities IMPLEMENTATION.
  METHOD describe_by_name.
    cl_abap_typedescr=>describe_by_name(
      EXPORTING
        p_name         = ig_name
      RECEIVING
        p_descr_ref    = ro_descr
      EXCEPTIONS
        type_not_found = 1
        OTHERS         = 2
    ).
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE zcx_type_not_found
        MESSAGE ID sy-msgid
        TYPE sy-msgty
        NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

TRY.
    DATA(lo_descr) = CAST cl_abap_structdescr( zcl_rtti_utilities=>describe_by_name( 'T000' ) ).
  CATCH zcx_type_not_found cx_sy_move_cast_error.
    ASSERT 1 = 2.
ENDTRY.

If you want a cleaner way to call the standard API maybe this helps?

cl_abap_typedescr=>describe_by_name( EXPORTING p_name          = 'T000'
                                     RECEIVING p_descr_ref     = DATA(lo_descr)
                                     EXCEPTIONS type_not_found = 1 ).
DATA(lo_struct_descr) = CAST cl_abap_structdescr(
                          COND #( WHEN sy-subrc = 0 THEN lo_descr
                                  ELSE THROW zcx_type_not_found(
                                               MESSAGE ID sy-msgid
                                               TYPE sy-msgty
                                               NUMBER sy-msgno
                                               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4
                                             ) )
                        ).

I personally most of the time don't catch type_not_found at all. Then you can use the functional method call in expressions etc. In my use cases if type_not_found is raised then this indicates a programming error (because I probably got the type name using RTTI anyways beforehand). And therefore a dump is just as fine as an assertion error.

https://blogs.sap.com/2015/11/12/abap-news-for-release-750-converting-messages-into-exceptions/

https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abenconditional_ex...

https://help.sap.com/http.svc/rc/abapdocu_751_index_htm/7.51/en-US/index.htm?file=abenif_t100_dyn_ms...

0 Kudos

Thanks a lot for taking time and replying Fabian.

Unfortunately, I don't have the luxury of playing with your code as it is in my system. Reason : My ABAP version doesn't support CAST key word nor DATA just before declaring it in FM / before actual usage. I have to make your code in traditional way to get it work in my system. However, when I move it to the traditional way, it is as same as what I have given in my question latter part 🙂

However, I think I can mark yours as answer by stating, with ECC 6 EhP4, I cannot do below

DATA: cl_workarea     TYPE REF TO cl_abap_elemdescr.
DATA: cl_wwarea       TYPE REF TO cl_abap_typedescr.
***********This type of casting and calling will not work in my version ECC6 EhP4. 
cl_workarea ?= cl_abap_elemdescr=>describe_by_name( EXPORTING p_name          = 'T000'
                                                    RECEIVING p_descr_ref     = cl_wwarea
                                                    EXCEPTIONS type_not_found = 1 ).
************We can call it this way and cast it later
cl_abap_elemdescr=>describe_by_name( EXPORTING p_name          = 'T000'
                                     RECEIVING p_descr_ref     = cl_wwarea
                                     EXCEPTIONS type_not_found = 1 ).
cl_workarea ?= cl_wwarea.
dd_dfies = cl_workarea->get_ddic_field( ).

*************(Or) this way and cast it later
CALL METHOD cl_abap_elemdescr=>describe_by_name
  EXPORTING
    p_name         = 'KATNR'
  receiving
    p_descr_ref    = cl_wwarea
  EXCEPTIONS
    type_not_found = 1
    others         = 2.
cl_workarea ?= cl_wwarea.
dd_dfies = cl_workarea->get_ddic_field( ).

and Yes... Thanks for the links 🙂

Again, you have forgotten to handle the exception by testing SY-SUBRC after CALL METHOD ... EXCEPTIONS ...

ha ha ha.... Since this is only an Example, I just typed the code to explain. Nevertheless, example should be an example. so correcting it to register in the thread. Thanks....

************We can call it this way and cast it later
cl_abap_elemdescr=>describe_by_name( EXPORTING p_name          = 'T000'
                                     RECEIVING p_descr_ref     = cl_wwarea
                                     EXCEPTIONS type_not_found = 1 ).
IF sy-subrc EQ 0.
  cl_workarea ?= cl_wwarea.
  dd_dfies = cl_workarea->get_ddic_field( ).
ENDIF.
*************(Or) this way and cast it later
CALL METHOD cl_abap_elemdescr=>describe_by_name
  EXPORTING
    p_name         = 'KATNR'
  receiving
    p_descr_ref    = cl_wwarea
  EXCEPTIONS
    type_not_found = 1
    others         = 2.
IF sy-subrc EQ 0.
  cl_workarea ?= cl_wwarea.
  dd_dfies = cl_workarea->get_ddic_field( ).
ENDIF.

pokrakam
Active Contributor

"...which reads Z program lines and find the appropriate domain attributes of the data declared in the program."

Are you aware that these days inline declarations are the preferred way of declaring data in many cases?

e.g. how would you go about determining the domain attributes of lo_descr in Fabian's second example? I can think of a few ways, but nothing without major effort.