Friday, 23 March 2018

ABAP Debugger Script – 2 use cases ( display object data in ALV / break condtion on object value)

In the project we came across the challenge to find information within a list of objects in the debugger. in the ALV display you will only see all the objects instances.

Using debugger scripts (basics here) you are able to iterate on the internal object table and work with the values. In the second example I will show you how to display object information in an ALV.

Using conditional breakpoints helps if there is a loop over all these objects in the #ABAP code. In the first example we will have the same functionality using a script, but in the end this could be much more powerful using more feature of the ABAP language if the conditions are met.

I wrote a demo Report that includes two other reports aka debugger scripts at the bottom to use with this report. It is based on the sflight table and should  compile on >NW7.10. ( if not just change these fancy modern commands ). The report selects 50 lines of sflight and creates a table of simple POAOs where the data is stored inside the objects only. These objects are defined in the top of the report.

One of the mayor issues / security features of debugger scrips is that you can not create them in a non open SAP System. If needed you should integrate them somehow in your Transports manually.

Let’s start.

1.  Copy the report at the end of the post into your system.

2. Run it and your debugger will stop:

ABAP Debugger Script, SAP ABAP Development, SAP ABAP Tutorials and Materials

3. Now we switch to the “Script” tab.

Here we can do all the scripting. Copy the local class of the first script report below and remove 3 columns of * comments.

ABAP Debugger Script, SAP ABAP Development, SAP ABAP Tutorials and Materials

Pay attention that “Debugger Single Step” is selected an run the script.

ABAP Debugger Script, SAP ABAP Development, SAP ABAP Tutorials and Materials

4. The debugger stopps within the loop at sy-tabix 27 where the object contains the requested payment_sum. Great!

Ok, this is also possible using conditional breakpoints in such a simple scenario.

Second Example

Let’s make it a bit more complex.

Now we want to see all the information of the object before we iterate over them.

5. Run the program again, when the debugger stopps you paste the code of the second local class.

ABAP Debugger Script, SAP ABAP Development, SAP ABAP Tutorials and Materials

Run the script again and you will see an ALV with the listes information of the classes.

ABAP Debugger Script, SAP ABAP Development, SAP ABAP Tutorials and Materials

There is much more documentation

*&---------------------------------------------------------------------*
*& Report ZTJ_DEBUGGER_SCRIPT_TEST
*&---------------------------------------------------------------------*
*& Report to demonstrate the power of ABAP debugger scripts
*& using to examples:
*& A) z_rstpda_script_obj_tab_2_alv
*&     Debugger script to list attribute values of a table of object instances in an ALV
*& B) z_rstpda_script_table_iteratio
*&    break if during loop of ABAP program a certain value within an object is found
*&
*& Report is based on the SAP flight model data.
*&
*& Created by: @Timo_Tohn 2018.
*& https://blogs.sap.com/2018/01/29/abap-debugger-script-2-use-cases/
*&---------------------------------------------------------------------*
REPORT ztj_debugger_script_test.
CLASS lcl_flight DEFINITION DEFERRED.
TYPES: " Object instance table
       tt_flights TYPE STANDARD TABLE OF REF TO lcl_flight WITH DEFAULT KEY.

CLASS lcl_flight DEFINITION CREATE PUBLIC.

  PUBLIC SECTION.
    CLASS-METHODS:
      get_list
        RETURNING VALUE(rt_flight_list) TYPE tt_flights.
    METHODS:
      constructor IMPORTING is_sflight TYPE sflight.

  PROTECTED SECTION.
  PRIVATE SECTION.
    DATA: mv_connid     TYPE sflight-carrid,
          mv_fldate     TYPE sflight-fldate,
          mv_paymentsum TYPE sflight-paymentsum.

ENDCLASS.

CLASS lcl_flight IMPLEMENTATION.

  METHOD constructor.
    me->mv_connid     = is_sflight-connid.
    me->mv_fldate     = is_sflight-fldate.
    me->mv_paymentsum = is_sflight-paymentsum.
  ENDMETHOD.

  METHOD get_list.
    SELECT * FROM sflight INTO TABLE @DATA(lt_flights) UP TO 50 ROWS.
    " create table with object instances
    rt_flight_list = VALUE #( FOR <wa> IN lt_flights (  NEW lcl_flight( <wa> )   ) ).

  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.

" Init object table.
  DATA(lt_fligt_insts) = lcl_flight=>get_list( ).


* Statements for debugging.
  WRITE 'Start Loop'.
  break-point.  " -> Now start the scripts.
  " - z_rstpda_script_table_iteratio
  " - z_rstpda_script_obj_tab_2_alv

  LOOP AT lt_fligt_insts INTO DATA(lo_flight).

    WRITE 'sy-tabix: ' && sy-tabix.

    CLEAR lo_flight. " we clear the object to test that scripts handle the occuring exceptions corretct.

    WRITE /.

  ENDLOOP.


  Exit.


********************************************************
* Save these two reports below as independent reports in your system to use them as Scripts.
* OR paste the local classes accordingly into the debugger script tab (only one at a time).
* then use Start "Start Script".

****<SCRIPT:PERSISTENT>
***REPORT z_rstpda_script_table_iteratio.
***
****<SCRIPT:HEADER>
****<SCRIPTNAME>Z_RSTPDA_SCRIPT_TABLE_ITERATIO</SCRIPTNAME>
****<SCRIPT_CLASS>LCL_DEBUGGER_SCRIPT</SCRIPT_CLASS>
****<SCRIPT_COMMENT>Anhalen bei komplexem Wert innerhalb einer Tabelleniteration</SCRIPT_COMMENT>
****<SINGLE_STEP>X</SINGLE_STEP>
***
****</SCRIPT:HEADER>
***
****<SCRIPT:PRESETTINGS>
***
****</SCRIPT:PRESETTINGS>
***
****<SCRIPT:SCRIPT_CLASS>
****---------------------------------------------------------------------*
****       CLASS lcl_debugger_script DEFINITION
****---------------------------------------------------------------------*
**** Debugger script to break if during loop of ABAP program a certain
**** value within an object is found.
****
**** Created by: @Timo_Tohn 2018.
****---------------------------------------------------------------------*
***CLASS lcl_debugger_script DEFINITION INHERITING FROM  cl_tpda_script_class_super  .
***
***  PUBLIC SECTION.
***    METHODS: script  REDEFINITION.
***ENDCLASS.                    "lcl_debugger_script DEFINITION
****---------------------------------------------------------------------*
****       CLASS lcl_debugger_script IMPLEMENTATION
****---------------------------------------------------------------------*
****
****---------------------------------------------------------------------*
***CLASS lcl_debugger_script IMPLEMENTATION.
***
***  METHOD script.
***    " Place the name of the variable that changes with each iteration and that is to be checked
***    " in this case we wait for a certain vbeln.
***    DATA: searched_sum TYPE sflight-paymentsum VALUE '486336.03'.
***
***    TRY.
***        DATA(lv_paymentsum) = cl_tpda_script_data_descr=>get_simple_value( 'lo_flight->mv_PAYMENTSUM' ).
***        "  BREAK-POINT.
***        IF lv_paymentsum = searched_sum.
***          " We want to stop if the flight with the specific payment value is found.
***          me->break( ).
***        ENDIF.
***      CATCH cx_tpda_varname
***            cx_tpda_script_no_simple_type.
***            " no need to react on these exceptions here, we just want to continue.
***    ENDTRY.
***
***  ENDMETHOD.                    "script
***ENDCLASS.                    "lcl_debugger_script IMPLEMENTATION
****</SCRIPT:SCRIPT_CLASS>
***
****</SCRIPT:PERSISTENT>


*****************************************************


****<SCRIPT:PERSISTENT>
***REPORT  z_rstpda_script_obj_tab_2_alv.
***
****<SCRIPT:HEADER>
****<SCRIPTNAME>Z_RSTPDA_SCRIPT_OBJ_TAB_2_ALV</SCRIPTNAME>
****<SCRIPT_CLASS>LCL_DEBUGGER_SCRIPT</SCRIPT_CLASS>
****<SINGLE_STEP>X</SINGLE_STEP>
***
****</SCRIPT:HEADER>
***
****<SCRIPT:PRESETTINGS>
***
****</SCRIPT:PRESETTINGS>
***
****<SCRIPT:SCRIPT_CLASS>
****---------------------------------------------------------------------*
****       CLASS lcl_debugger_script DEFINITION
****---------------------------------------------------------------------*
**** Debugger script to list attribute values of a table of object
**** instances in an ALV.
****
**** Created by: @Timo_Tohn 2018.
****---------------------------------------------------------------------*
***CLASS lcl_debugger_script DEFINITION INHERITING FROM  cl_tpda_script_class_super  .
***
***  PUBLIC SECTION.
***    METHODS: script  REDEFINITION.
***
***  PRIVATE SECTION.
***    TYPES: BEGIN OF ts_alv_data,
***             "! like ->{O:10*\PROGRAM=ZTJ_DEBUGGER_SCRIPT_TEST\CLASS=LCL_FLIGHT}
***             instance_reference TYPE char100,
***             connid             TYPE sflight-connid,
***             fldate             TYPE  sflight-fldate,
***             paymentsum         TYPE  sflight-paymentsum,
***           END OF ts_alv_data.
***
***    DATA:
***      "! ALV display table
***      mt_alv_data  TYPE STANDARD TABLE OF ts_alv_data,
***      "! Name of the with objekt instances of the program.
***      mv_tablename TYPE string.
***
***
***ENDCLASS.                    "lcl_debugger_script DEFINITION
****---------------------------------------------------------------------*
****       CLASS lcl_debugger_script IMPLEMENTATION
****---------------------------------------------------------------------*
****
****---------------------------------------------------------------------*
***CLASS lcl_debugger_script IMPLEMENTATION.
***
***  METHOD script.
***    DATA: lo_table_descr TYPE REF TO cl_tpda_script_tabledescr,
***          table_clone    TYPE REF TO data.
***
***    FIELD-SYMBOLS: <table_clone> TYPE table,
***                   <l_clone>     TYPE any.
***
***    "BREAK-POINT. " if you want to debug the script use this.
***
***    FREE mt_alv_data. " to clean it for every run.
***    mv_tablename = 'LT_FLIGT_INSTS'.
***
***    lo_table_descr ?= cl_tpda_script_data_descr=>factory( mv_tablename ).
***    table_clone =  lo_table_descr->elem_clone( ).
***    ASSIGN table_clone->* TO <table_clone>.
***
***    "Loop over cloned table from program. unfortunately the objects are not cloned, only the names of references are in there.
***    LOOP AT <table_clone> ASSIGNING <l_clone>.
***      APPEND INITIAL LINE TO mt_alv_data ASSIGNING FIELD-SYMBOL(<s_alv_data>).
***
***      " disply the instance number as well
***      <s_alv_data>-instance_reference = <l_clone>+2 . "+2 to eliminate the "->"
***
***      "Now we concatenate the specific name of the variable as we would type it in the debugger variables
***      "and query the information from the object instances to put it into ALV-table.
***      <s_alv_data>-connid = cl_tpda_script_data_descr=>get_simple_value( <s_alv_data>-instance_reference && '-mv_connid' ).
***      <s_alv_data>-paymentsum = cl_tpda_script_data_descr=>get_simple_value( <s_alv_data>-instance_reference && '-mv_paymentsum' ).
***      <s_alv_data>-fldate = cl_tpda_script_data_descr=>get_simple_value( <s_alv_data>-instance_reference && '-mv_fldate' ).
***    ENDLOOP.
****   With the collected ALV Table we can do what ever is interesting for us in that moment.
****   Set up the ALV table for displaying the data.
***    cl_tpda_script_data_display=>data_display( CHANGING  p_data_it = mt_alv_data ).
***    me->break( ).
***
***  ENDMETHOD.                    "script
***ENDCLASS.                    "lcl_debugger_script IMPLEMENTATION
****</SCRIPT:SCRIPT_CLASS>
***
****</SCRIPT:PERSISTENT>

No comments:

Post a Comment