├── .abapgit.xml ├── LICENSE ├── README.md ├── package.devc.xml ├── z_debug_obj_service_graph.enho.xml ├── z_debug_obj_service_graph_var.enho.xml ├── zcl_debug_obj_graph_factory.clas.abap ├── zcl_debug_obj_graph_factory.clas.locals_def.abap ├── zcl_debug_obj_graph_factory.clas.locals_imp.abap ├── zcl_debug_obj_graph_factory.clas.xml ├── zcl_debug_obj_to_graph.clas.abap └── zcl_debug_obj_to_graph.clas.xml /.abapgit.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | E 6 | / 7 | PREFIX 8 | 9 | /.gitignore 10 | /LICENSE 11 | /README.md 12 | /package.json 13 | /.travis.yml 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Marcello Urbani 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Abap debugger object graph extension 2 | 3 | ABAP debugger extension to visualize objects as graphs via [graphviz](http://www.graphviz.org/) 4 | 5 | ### Installation 6 | 7 | The prerequisite [ABAP Graph](https://github.com/marcellourbani/abapgraph) needs to be installed first, then install via [abapGit](https://github.com/larshp/abapGit) 8 | 9 | Tested on netweaver 7.5, not sure about older releases 10 | 11 | ### Use 12 | 13 | 1. Set breakpoint in source code 14 | 2. In the new debugger go to "Objects" tab 15 | 3. open the tools menu from the icon on the left ![image](https://user-images.githubusercontent.com/2453277/44873462-39cffc00-ac90-11e8-8815-45b797085919.png) 16 | 17 | 4. select **View object as graph** 18 | 19 | The object graph will be shown in a new browser window (Example from http://zevolving.com/2012/01/iterator-design-pattern-to-access-linked-list/ ) 20 | 21 | ![image](https://user-images.githubusercontent.com/2453277/45267892-94c1da00-b46c-11e8-8759-411cb635c4d2.png) 22 | 23 | Another example from the excellent [Writing Testable Code for ABAP](https://open.sap.com/courses/wtc1) opensap course 24 | ![image](https://user-images.githubusercontent.com/2453277/45267904-ed917280-b46c-11e8-8c6c-d57bd72083fa.png) 25 | 26 | Originally inspired by 27 | [ABAP-Object-Visualizer](https://github.com/larshp/ABAP-Object-Visualizer) 28 | 29 | Uses [Graphviz-browser](https://github.com/marcellourbani/Graphviz-browser) to render the graph in a browser window 30 | -------------------------------------------------------------------------------- /package.devc.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Object graph viewer for debug tool 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /z_debug_obj_service_graph.enho.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | HOOK_IMPL 6 | Graph display for object 7 | 8 | R3TR 9 | CLAS 10 | CL_TPDA_TOOL_OBJECT_VIEW 11 | CLAS 12 | CL_TPDA_TOOL_OBJECT_VIEW 13 | CL_TPDA_TOOL_OBJECT_VIEW======CP 14 | 15 | 16 | 17 | CL_TPDA_TOOL_OBJECT_VIEW======CP 18 | 1 19 | 1 20 | D 21 | \TY:CL_TPDA_TOOL_OBJECT_VIEW\IN:IF_TPDA_TOOL_SERVICES\ME:BUILD_SERVICES_MENUE\SE:END\EI 22 | 23 | DATA l_zz_node LIKE LINE OF p_it_menue_tree. 24 | CLEAR l_zz_node. 25 | 26 | l_zz_node-node_key = 'ZOBJEXPORTGR'. 27 | l_zz_node-relatkey = cl_tpda_services_tools=>c_special. 28 | l_zz_node-n_image = cl_tpda_icons=>TPDA_ICON_EDITOR_VIEW. 29 | l_zz_node-relatship = cl_gui_simple_tree=>relat_last_child. 30 | l_zz_node-text = 'View object as graph'. 31 | 32 | APPEND l_zz_node TO p_it_menue_tree. 33 | 34 | 35 | 36 | CL_TPDA_TOOL_OBJECT_VIEW======CP 37 | 2 38 | 2 39 | D 40 | \TY:CL_TPDA_TOOL_OBJECT_VIEW\IN:IF_TPDA_TOOL_SERVICES\ME:HANDLE_SERVICE_REQUEST\SE:BEGIN\EI 41 | 42 | data: zzl_node_key like line of p_it_selected_node, 43 | zdebgr type ref to ZCL_DEBUG_OBJ_TO_GRAPH, 44 | zz_exception type ref to cx_root. 45 | read table p_it_selected_node INTO zzl_node_key INDEX 1. 46 | if zzl_node_key = 'ZOBJEXPORTGR'. 47 | try. 48 | create object zdebgr. 49 | zdebgr->display_graph( dynp_vars-object_name_real ). 50 | catch cx_sy_no_handler into zz_exception . 51 | message zz_exception->previous type 'I'. 52 | catch cx_root into zz_exception . 53 | message zz_exception type 'I'. 54 | endtry. 55 | exit. 56 | endif. 57 | 58 | 59 | 60 | 61 | 62 | \TY:CL_TPDA_TOOL_OBJECT_VIEW\IN:IF_TPDA_TOOL_SERVICES\ME:BUILD_SERVICES_MENUE\SE:END\EI 63 | 64 | 1 65 | 1 66 | 0 67 | 1 68 | 1 69 | 1 70 | 1 71 | 1 72 | 0 73 | 1 74 | 75 | 76 | 77 | \TY:CL_TPDA_TOOL_OBJECT_VIEW\IN:IF_TPDA_TOOL_SERVICES\ME:HANDLE_SERVICE_REQUEST\SE:BEGIN\EI 78 | 79 | 2 80 | 14 81 | 14 82 | 3 83 | 4 84 | 6 85 | 8 86 | 8 87 | 4 88 | 7 89 | 4 90 | 7 91 | 4 92 | 4 93 | 2 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /z_debug_obj_service_graph_var.enho.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | HOOK_IMPL 6 | Display variable graph 7 | 8 | R3TR 9 | CLAS 10 | CL_TPDA_TOOL_QUICK_VARS 11 | CLAS 12 | CL_TPDA_TOOL_QUICK_VARS 13 | CL_TPDA_TOOL_QUICK_VARS=======CP 14 | 15 | 16 | 17 | CL_TPDA_TOOL_QUICK_VARS=======CP 18 | 1 19 | 1 20 | D 21 | \TY:CL_TPDA_TOOL_QUICK_VARS\IN:IF_TPDA_TOOL_SERVICES\ME:BUILD_SERVICES_MENUE\SE:END\EI 22 | 23 | DATA l_zz_node LIKE LINE OF p_it_menue_tree. 24 | CLEAR l_zz_node. 25 | 26 | l_zz_node-node_key = 'ZOBJEXPORTGR'. 27 | l_zz_node-relatkey = cl_tpda_services_tools=>c_special. 28 | l_zz_node-n_image = cl_tpda_icons=>TPDA_ICON_EDITOR_VIEW. 29 | l_zz_node-relatship = cl_gui_simple_tree=>relat_last_child. 30 | l_zz_node-text = 'View object as graph'. 31 | 32 | APPEND l_zz_node TO p_it_menue_tree. 33 | 34 | 35 | 36 | CL_TPDA_TOOL_QUICK_VARS=======CP 37 | 2 38 | 2 39 | D 40 | \TY:CL_TPDA_TOOL_QUICK_VARS\IN:IF_TPDA_TOOL_SERVICES\ME:HANDLE_SERVICE_REQUEST\SE:BEGIN\EI 41 | 42 | data: zzl_node_key like line of p_it_selected_node, 43 | zdebgr type ref to ZCL_DEBUG_OBJ_TO_GRAPH, 44 | zz_var_name type string, 45 | zz_exception type ref to cx_root. 46 | read table p_it_selected_node INTO zzl_node_key INDEX 1. 47 | 48 | if zzl_node_key = 'ZOBJEXPORTGR'. 49 | try. 50 | create object zdebgr. 51 | zz_var_name = zdebgr->popup( ). 52 | if zz_var_name <> ''. 53 | zdebgr->display_graph( zz_var_name ). 54 | endif. 55 | catch cx_sy_no_handler into zz_exception . 56 | message zz_exception->previous type 'I'. 57 | catch cx_root into zz_exception . 58 | message zz_exception type 'I'. 59 | endtry. 60 | 61 | exit. 62 | endif. 63 | 64 | 65 | 66 | 67 | 68 | \TY:CL_TPDA_TOOL_QUICK_VARS\IN:IF_TPDA_TOOL_SERVICES\ME:BUILD_SERVICES_MENUE\SE:END\EI 69 | 70 | 1 71 | 1 72 | 0 73 | 1 74 | 1 75 | 1 76 | 1 77 | 1 78 | 0 79 | 1 80 | 81 | 82 | 83 | \TY:CL_TPDA_TOOL_QUICK_VARS\IN:IF_TPDA_TOOL_SERVICES\ME:HANDLE_SERVICE_REQUEST\SE:BEGIN\EI 84 | 85 | 2 86 | 9 87 | 9 88 | 9 89 | 3 90 | 0 91 | 3 92 | 5 93 | 8 94 | 8 95 | 8 96 | 10 97 | 8 98 | 5 99 | 7 100 | 5 101 | 7 102 | 5 103 | 0 104 | 5 105 | 3 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /zcl_debug_obj_graph_factory.clas.abap: -------------------------------------------------------------------------------- 1 | class zcl_debug_obj_graph_factory definition public final create public . 2 | 3 | public section. 4 | class-methods create importing i_max_tab_lines type i default 200 5 | returning value(r_result) type ref to zcl_debug_obj_graph_factory. 6 | 7 | methods: create_graph importing root type string 8 | returning value(graph) type ref to zcl_abap_graph. 9 | 10 | data: max_tab_lines type i read-only, 11 | logs type string read-only. 12 | 13 | private section. 14 | constants: c_headerbg type string value 'lavender', 15 | c_privatebg type string value 'lightsalmon', 16 | c_protectedbg type string value 'khaki'. 17 | 18 | types: begin of ty_type_desc, 19 | name type string, 20 | local type abap_bool, 21 | end of ty_type_desc, 22 | begin of ty_data_desc, 23 | name type string, 24 | descr type ref to cl_tpda_script_data_descr, 25 | refname type string, 26 | valuetext type string, 27 | typedesc type ty_type_desc, 28 | metatype type tpda_scr_quick_info-metatype, 29 | hascomponents type abap_bool, 30 | istable type abap_bool, 31 | isreference type abap_bool, 32 | haschildren type abap_bool, 33 | end of ty_data_desc, 34 | begin of ty_component, 35 | compname type string, 36 | value type string, 37 | desc type ty_data_desc, 38 | visibility type i, 39 | end of ty_component, 40 | tt_component type table of ty_component with default key. 41 | 42 | constants: c_public type i value 0, 43 | c_protected type i value 1, 44 | c_private type i value 2, 45 | c_dummy type string value 'DUMMY'. 46 | data: graph type ref to zcl_abap_graph. 47 | 48 | methods create_node_new importing desc type zcl_debug_obj_graph_factory=>ty_data_desc 49 | returning value(node) type ref to zif_abap_graph_node. 50 | 51 | methods get_or_create_node importing name type string 52 | returning value(nodeid) type string. 53 | 54 | methods get_node_id importing name type string 55 | returning value(id) type string. 56 | 57 | 58 | methods escapevalue importing original type string 59 | returning value(escaped) type string. 60 | 61 | methods get_data_desc importing name type string 62 | returning value(desc) type ty_data_desc. 63 | 64 | methods create_table_node importing desc type zcl_debug_obj_graph_factory=>ty_data_desc 65 | returning value(node) type ref to zif_abap_graph_node. 66 | 67 | methods create_record_node importing desc type zcl_debug_obj_graph_factory=>ty_data_desc 68 | returning value(node) type ref to zif_abap_graph_node. 69 | 70 | methods create_simple_node importing desc type zcl_debug_obj_graph_factory=>ty_data_desc 71 | returning value(node) type ref to zif_abap_graph_node. 72 | 73 | methods get_components importing desc type zcl_debug_obj_graph_factory=>ty_data_desc 74 | returning value(components) type zcl_debug_obj_graph_factory=>tt_component. 75 | 76 | methods log importing entry type string. 77 | 78 | methods add_record_component importing record type ref to zcl_abap_graph_node_record 79 | component type zcl_debug_obj_graph_factory=>ty_component 80 | returning value(componentid) type string. 81 | 82 | methods get_value importing desc type ty_data_desc 83 | returning value(r_result) type string. 84 | 85 | methods get_head_label importing desc type ty_data_desc 86 | returning value(r_result) type string. 87 | 88 | methods decode_visibility importing acckind type i 89 | returning value(r_result) type i. 90 | 91 | methods decodetype importing typename type string 92 | desc type ty_data_desc 93 | returning value(td) type ty_type_desc. 94 | 95 | methods viscolor importing visibility type i 96 | returning value(r_result) type string. 97 | 98 | methods bold importing base type string 99 | returning value(r_result) type string. 100 | 101 | methods italics importing base type string 102 | returning value(r_result) type string. 103 | methods underline importing base type string 104 | returning value(r_result) type string. 105 | methods add_table_cell importing table type ref to zcl_abap_graph_node_table 106 | desc type zcl_debug_obj_graph_factory=>ty_data_desc 107 | line type i 108 | value(compname) type string 109 | returning value(componentid) type string. 110 | 111 | ENDCLASS. 112 | 113 | 114 | 115 | CLASS ZCL_DEBUG_OBJ_GRAPH_FACTORY IMPLEMENTATION. 116 | 117 | 118 | method add_record_component. 119 | data: id type string, 120 | partid type string, 121 | color type string, 122 | compname type string, 123 | value type string. 124 | 125 | id = component-desc-name . 126 | 127 | if component-desc-haschildren = abap_true. 128 | partid = component-compname. 129 | value = get_value( component-desc ). 130 | else. 131 | partid = ''. 132 | value = component-value . 133 | endif. 134 | compname = bold( component-compname ). 135 | 136 | color = viscolor( component-visibility ). 137 | componentid = record->addcomponent( 138 | name = compname 139 | value = value 140 | escape = abap_false 141 | bgcolor = color 142 | partid = partid ). 143 | 144 | endmethod. 145 | 146 | 147 | method add_table_cell. 148 | data: partid type string, 149 | value type string, 150 | linkedid type string. 151 | log( |R{ desc-refname }_C{ compname }_L{ line } | ). 152 | if desc-refname <> ''. 153 | if compname = ''. 154 | partid = |l{ line }|. 155 | else. 156 | partid = |l{ line }c{ compname }|. 157 | endif. 158 | else. 159 | partid = ''. 160 | endif. 161 | if compname = ''. 162 | compname = c_dummy. 163 | endif. 164 | 165 | value = get_value( desc ). 166 | 167 | log( |R{ desc-refname }_C{ componentid }_V{ value } | ). 168 | 169 | componentid = table->setcell( 170 | columnid = compname 171 | row = line 172 | value = value 173 | escape = abap_false 174 | partid = partid ). 175 | 176 | if desc-refname <> '' and componentid <> '' . 177 | linkedid = get_or_create_node( desc-refname ). 178 | if linkedid <> ''. 179 | table->linkto( destination = linkedid source = componentid ). 180 | endif. 181 | endif. 182 | 183 | endmethod. 184 | 185 | 186 | method bold. 187 | if base <> ''. 188 | concatenate '' base '' into r_result. 189 | endif. 190 | endmethod. 191 | 192 | 193 | method create. 194 | 195 | create object r_result. 196 | 197 | r_result->max_tab_lines = i_max_tab_lines. 198 | 199 | endmethod. 200 | 201 | 202 | method create_graph. 203 | data: desc type zcl_debug_obj_graph_factory=>ty_data_desc. 204 | 205 | graph = zcl_abap_graph=>create( ). 206 | me->graph = graph. 207 | 208 | desc = get_data_desc( root ). 209 | 210 | if desc is initial. 211 | message 'Variable not found' type 'S'. 212 | else. 213 | create_node_new( desc ). 214 | endif. 215 | 216 | endmethod. 217 | 218 | 219 | method create_node_new. 220 | 221 | if desc-istable = abap_true. 222 | node = create_table_node( desc ). 223 | elseif desc-hascomponents = abap_true. 224 | node = create_record_node( desc ). 225 | else. 226 | node = create_simple_node( desc ). 227 | endif. 228 | 229 | endmethod. 230 | 231 | 232 | method create_record_node. 233 | data: value type string, 234 | id type string, 235 | linkedid type string, 236 | components type tt_component, 237 | record type ref to zcl_abap_graph_node_record, 238 | componentid type string, 239 | ex type ref to cx_root. 240 | field-symbols: like line of components. 241 | 242 | try. 243 | components = get_components( desc ). 244 | 245 | value = get_head_label( desc ). 246 | id = desc-name . 247 | node = record = zcl_abap_graph_node_record=>create( graph = graph id = id label = value escape = abap_false ). 248 | record->headerattr->set( name = 'bgcolor' value = c_headerbg ). 249 | 250 | loop at components assigning . 251 | componentid = add_record_component( record = record component = ). 252 | 253 | if componentid <> ''. 254 | linkedid = get_or_create_node( -desc-refname ). 255 | if linkedid <> ''. 256 | node->linkto( destination = linkedid source = componentid ). 257 | endif. 258 | endif. 259 | 260 | endloop. 261 | catch cx_root into ex. 262 | log( |create_record_node exception { ex->get_text( ) } | ). 263 | endtry. 264 | endmethod. 265 | 266 | 267 | method create_simple_node. 268 | data: value type string, 269 | id type string, 270 | linkedid type string. 271 | 272 | value = desc-valuetext. 273 | id = desc-name . 274 | node = zcl_abap_graph_node_simple=>create( graph = graph id = id label = value ). 275 | 276 | if desc-haschildren = abap_true. 277 | linkedid = get_or_create_node( desc-refname ). 278 | if linkedid <> ''. 279 | node->linkto( linkedid ). 280 | endif. 281 | endif. 282 | 283 | endmethod. 284 | 285 | 286 | method create_table_node. 287 | data: value type string, 288 | id type string, 289 | components type tt_component, 290 | tabdesc type ref to cl_tpda_script_tabledescr, 291 | table type ref to zcl_abap_graph_node_table, 292 | linename type string, 293 | line type i, 294 | linedesc type zcl_debug_obj_graph_factory=>ty_data_desc, 295 | ex type ref to cx_root. 296 | field-symbols: like line of components. 297 | 298 | 299 | try. 300 | tabdesc ?= desc-descr. 301 | id = desc-name. 302 | value = get_head_label( desc ). 303 | log( |table { id }__{ value }| ). 304 | node = table = zcl_abap_graph_node_table=>create( graph = graph 305 | id = id 306 | label = value 307 | escape = abap_false ). 308 | table->headerattr->set( name = 'bgcolor' value = c_headerbg ). 309 | table->titleattr->set( name = 'bgcolor' value = c_headerbg ). 310 | 311 | do tabdesc->linecnt( ) times. 312 | line = sy-index. 313 | log( | table line { line } | ). 314 | linename = |{ desc-name }[{ line }]|. 315 | linedesc = get_data_desc( linename ). 316 | if line = 1 or not components is initial. 317 | components = get_components( linedesc ). 318 | if line = 1. 319 | "header 320 | if components is initial. 321 | table->setcolumn( id = c_dummy ). 322 | else. 323 | loop at components assigning . 324 | value = escapevalue( -compname ). 325 | value = bold( value ). 326 | table->setcolumn( id = -compname name = value ). 327 | endloop. 328 | endif. 329 | endif. 330 | endif. 331 | 332 | if components is initial. 333 | add_table_cell( table = table line = line desc = linedesc compname = '' ). 334 | else. 335 | "actual components of a line 336 | loop at components assigning . 337 | add_table_cell( table = table line = line desc = -desc compname = -compname ). 338 | endloop. 339 | endif. 340 | enddo. 341 | catch cx_root into ex. 342 | log( |create_table_node exception { ex->get_text( ) } | ). 343 | endtry. 344 | 345 | endmethod. 346 | 347 | 348 | method decodetype. 349 | data: base type string, 350 | extra type string. 351 | 352 | td-local = abap_true. 353 | td-name = typename. 354 | find regex '^\\TYPE=(.+)' in typename submatches base. 355 | if sy-subrc = 0. 356 | if base(1) = '%'. 357 | case desc-metatype. 358 | when cl_tpda_control=>mt_tab. 359 | base = 'table'. 360 | when cl_tpda_control=>mt_struct. 361 | base = 'structure'. 362 | when cl_tpda_control=>mt_class. 363 | base = 'class'. 364 | when others. 365 | base = 'type'. 366 | endcase. 367 | concatenate 'local ' base '' into base respecting blanks. 368 | else. 369 | td-local = abap_false. 370 | endif. 371 | td-name = base. 372 | return. 373 | endif. 374 | find regex '^\\PROGRAM=[^\\]*\\CLASS=([^\\]+)' in typename submatches base. 375 | if sy-subrc = 0. 376 | td-name = base. 377 | return. 378 | endif. 379 | find regex '^\\PROGRAM=[^\\]*\\CLASS=([^\\]+)' in typename submatches base. 380 | if sy-subrc = 0. 381 | td-name = base. 382 | return. 383 | endif. 384 | find regex '^\\CLASS-POOL=([^\\]+)\\CLASS=([^\\]+)' in typename submatches base extra. 385 | if sy-subrc = 0. 386 | concatenate base extra into td-name separated by space. 387 | return. 388 | endif. 389 | endmethod. 390 | 391 | 392 | method decode_visibility. 393 | case acckind. 394 | when if_tpda_control=>ak_private. 395 | r_result = c_private. 396 | when if_tpda_control=>ak_protected. 397 | r_result = c_protected. 398 | endcase. 399 | endmethod. 400 | 401 | 402 | method escapevalue. 403 | escaped = cl_http_utility=>escape_html( original ). 404 | endmethod. 405 | 406 | 407 | method get_components. 408 | data: odesc type ref to cl_tpda_script_objectdescr, 409 | sdesc type ref to cl_tpda_script_structdescr, 410 | tdesc type ref to cl_tpda_script_tabledescr, 411 | objattributes type tpda_script_object_attribut_it, 412 | scomponents type tpda_script_struc_componentsit, 413 | refname type string, 414 | match_offset type i, 415 | ex type ref to cx_root, 416 | basename type string. 417 | field-symbols: like line of scomponents, 418 | like line of components, 419 | like line of objattributes. 420 | try. 421 | 422 | case desc-metatype. 423 | when cl_tpda_script_data_descr=>mt_object. 424 | odesc ?= desc-descr. 425 | objattributes = odesc->attributes( ). 426 | when cl_tpda_script_data_descr=>mt_struct."struct 427 | sdesc ?= desc-descr. 428 | sdesc->components( importing p_components_it = scomponents ). 429 | find regex '\*$' in desc-name match offset match_offset. 430 | if match_offset = 0. 431 | basename = desc-name. 432 | else. 433 | basename = desc-name(match_offset). 434 | endif. 435 | basename = desc-name. 436 | when cl_tpda_script_data_descr=>mt_tab. 437 | tdesc ?= desc-descr. 438 | if tdesc->linecnt( ) > 0. 439 | log( |get_components probable casting exception after this line | ). 440 | sdesc ?= tdesc->get_line_handle( 1 ). 441 | sdesc->components( importing p_components_it = scomponents ). 442 | concatenate desc-name '[1]' into basename. 443 | endif. 444 | endcase. 445 | 446 | loop at objattributes assigning . 447 | append initial line to components assigning . 448 | -compname = -name. 449 | concatenate desc-name '-' -name into refname. 450 | -desc = get_data_desc( refname ). 451 | -visibility = decode_visibility( -acckind ). 452 | -value = get_value( -desc ). 453 | endloop. 454 | 455 | loop at scomponents assigning . 456 | append initial line to components assigning . 457 | -compname = -compname. 458 | -visibility = c_public. 459 | concatenate basename '-' -compname into refname. 460 | -desc = get_data_desc( refname ). 461 | -value = get_value( -desc ). 462 | endloop. 463 | 464 | catch cx_root into ex. 465 | log( |get_components { ex->get_text( ) } | ). 466 | endtry. 467 | if desc-metatype = cl_tpda_script_data_descr=>mt_object. 468 | sort components by visibility compname ascending. 469 | endif. 470 | endmethod. 471 | 472 | 473 | method get_data_desc. 474 | data: elem type ref to cl_tpda_script_elemdescr, 475 | string type ref to cl_tpda_script_stringdescr, 476 | table type ref to cl_tpda_script_tabledescr, 477 | odesc type ref to cl_tpda_script_objectdescr, 478 | info type tpda_scr_quick_info, 479 | ex type ref to cx_root. 480 | 481 | field-symbols: type tpda_sys_symbdatref, 482 | type tpda_sys_symbobjref. 483 | 484 | desc-name = name. 485 | 486 | try. 487 | desc-descr = cl_tpda_script_data_descr=>factory( name ). 488 | info = cl_tpda_script_data_descr=>get_quick_info( name ). 489 | desc-metatype = info-metatype. 490 | case info-metatype. 491 | when cl_tpda_script_data_descr=>mt_string. 492 | string ?= desc-descr. 493 | desc-valuetext = string->value( ). 494 | desc-valuetext = cl_http_utility=>escape_html( desc-valuetext ). 495 | when cl_tpda_script_data_descr=>mt_simple. 496 | elem ?= desc-descr. 497 | desc-valuetext = elem->value( ). 498 | desc-valuetext = cl_http_utility=>escape_html( desc-valuetext ). 499 | when cl_tpda_script_data_descr=>mt_struct. 500 | " desc-valuetext = cl_http_utility=>escape_html( info-abstypename ). 501 | desc-typedesc = decodetype( typename = info-abstypename desc = desc ). 502 | desc-hascomponents = abap_true. 503 | desc-haschildren = abap_true. 504 | desc-refname = name. 505 | when cl_tpda_script_data_descr=>mt_tab. 506 | table ?= desc-descr. 507 | if table->linecnt( ) > 0. 508 | desc-haschildren = abap_true. 509 | desc-istable = abap_true. 510 | desc-valuetext = ''. 511 | desc-refname = name. 512 | else. 513 | desc-valuetext = ''. 514 | endif. 515 | desc-typedesc = decodetype( typename = info-abstypename desc = desc ). 516 | when cl_tpda_script_data_descr=>mt_datref. 517 | assign info-quickdata->* to . 518 | find regex '^\{[A-Z]:initial\}$' in -instancename ignoring case. 519 | desc-isreference = abap_true. 520 | if sy-subrc <> 0. 521 | desc-haschildren = abap_true. 522 | desc-refname = -instancename. 523 | desc-valuetext = ''. 524 | else. 525 | desc-valuetext = ''. 526 | endif. 527 | when cl_tpda_script_data_descr=>mt_object. 528 | desc-haschildren = abap_true. 529 | desc-hascomponents = abap_true. 530 | odesc ?= desc-descr. 531 | desc-valuetext = odesc->classname( ). 532 | desc-typedesc = decodetype( typename = desc-valuetext desc = desc ). 533 | when cl_tpda_script_data_descr=>mt_objref. 534 | assign info-quickdata->* to . 535 | if -instancename <> '{O:initial}'. 536 | desc-haschildren = abap_true. 537 | desc-refname = -instancename. 538 | desc-valuetext = ''. 539 | else. 540 | desc-valuetext = ''. 541 | endif. 542 | desc-isreference = abap_true. 543 | endcase. 544 | catch cx_root into ex. 545 | clear desc. 546 | log( |get_data_desc exception { ex->get_text( ) } | ). 547 | endtry. 548 | 549 | endmethod. 550 | 551 | 552 | method get_head_label. 553 | if desc-istable = abap_true 554 | or desc-hascomponents = abap_true 555 | or desc-isreference = abap_true. 556 | r_result = escapevalue( desc-typedesc-name ). 557 | if desc-typedesc-local = abap_true. 558 | r_result = italics( r_result ). 559 | endif. 560 | endif. 561 | if r_result is initial. 562 | r_result = escapevalue( desc-valuetext ). 563 | endif. 564 | endmethod. 565 | 566 | 567 | method get_node_id. 568 | id = name. 569 | endmethod. 570 | 571 | 572 | method get_or_create_node. 573 | data: desc type zcl_debug_obj_graph_factory=>ty_data_desc, 574 | node type ref to zif_abap_graph_node. 575 | 576 | node = graph->get_node( name ). 577 | 578 | if not node is bound. 579 | "look up cache 580 | desc = get_data_desc( name ). 581 | node = create_node_new( desc ). 582 | endif. 583 | 584 | if node is bound. 585 | nodeid = node->id. 586 | endif. 587 | 588 | endmethod. 589 | 590 | 591 | method get_value. 592 | if desc-istable = abap_true 593 | or desc-hascomponents = abap_true 594 | or desc-isreference = abap_true. 595 | r_result = escapevalue( desc-typedesc-name ). 596 | if desc-typedesc-local = abap_true. 597 | r_result = italics( r_result ). 598 | endif. 599 | r_result = underline( r_result ). 600 | if r_result is initial. 601 | r_result = escapevalue( desc-valuetext ). 602 | endif. 603 | endif. 604 | 605 | if r_result is initial. 606 | r_result = escapevalue( desc-valuetext ). 607 | endif. 608 | 609 | endmethod. 610 | 611 | 612 | method italics. 613 | if base <> ''. 614 | concatenate '' base '' into r_result. 615 | endif. 616 | endmethod. 617 | 618 | 619 | method log. 620 | logs = |{ logs }{ cl_abap_char_utilities=>cr_lf }{ entry }|. 621 | endmethod. 622 | 623 | 624 | method underline. 625 | if base <> ''. 626 | concatenate '' base '' into r_result. 627 | endif. 628 | endmethod. 629 | 630 | 631 | method viscolor. 632 | 633 | case visibility. 634 | when c_protected. 635 | r_result = c_protected. 636 | when c_private. 637 | r_result = c_privatebg. 638 | endcase. 639 | 640 | endmethod. 641 | ENDCLASS. 642 | -------------------------------------------------------------------------------- /zcl_debug_obj_graph_factory.clas.locals_def.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for any type of declarations (class 2 | *"* definitions, interfaces or type declarations) you need for 3 | *"* components in the private section 4 | class bd definition inheriting from CL_TPDA_SCRIPT_DATA_DESCR. 5 | public section. 6 | class-methods:vname importing descr type ref to CL_TPDA_SCRIPT_DATA_DESCR 7 | returning value(varname) type string. 8 | endclass. 9 | -------------------------------------------------------------------------------- /zcl_debug_obj_graph_factory.clas.locals_imp.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for the definition and implementation of 2 | *"* local helper classes, interface definitions and type 3 | *"* declarations 4 | 5 | 6 | class bd implementation. 7 | 8 | method vname. 9 | varname = descr->var_name. 10 | endmethod. 11 | 12 | endclass. 13 | -------------------------------------------------------------------------------- /zcl_debug_obj_graph_factory.clas.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | ZCL_DEBUG_OBJ_GRAPH_FACTORY 7 | 1 8 | E 9 | Graph object factory 10 | 2 11 | 1 12 | X 13 | X 14 | X 15 | X 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /zcl_debug_obj_to_graph.clas.abap: -------------------------------------------------------------------------------- 1 | ******************************************************************************** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 Marcello Urbani 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | ******************************************************************************** 24 | class zcl_debug_obj_to_graph definition public final create public . 25 | 26 | public section. 27 | 28 | methods display_graph importing !name type string. 29 | methods popup returning value(varname) type string. 30 | protected section. 31 | private section. 32 | 33 | constants c_newline like cl_abap_char_utilities=>newline value cl_abap_char_utilities=>newline ##NO_TEXT. 34 | 35 | data uploadpath type string. 36 | data downloadpath type string. 37 | 38 | 39 | methods get_temp_file_url 40 | returning 41 | value(r_result) type string. 42 | 43 | 44 | endclass. 45 | 46 | 47 | 48 | class zcl_debug_obj_to_graph implementation. 49 | 50 | method display_graph. 51 | data: lx_root type ref to cx_root, 52 | factory type ref to zcl_debug_obj_graph_factory, 53 | graph type ref to zcl_abap_graph. 54 | try. 55 | if name is initial. 56 | return. 57 | endif. 58 | factory = zcl_debug_obj_graph_factory=>create( ). 59 | graph = factory->create_graph( name ). 60 | if graph is bound. 61 | zcl_abap_graph_utilities=>show_in_browser( graph = graph comments = factory->logs ). 62 | else. 63 | message 'Unknown variable'(006) type 'I'. 64 | endif. 65 | 66 | catch cx_tpda_varname. 67 | message 'Unknown variable'(006) type 'I'. 68 | catch cx_root into lx_root. 69 | message lx_root type 'I'. 70 | endtry. 71 | 72 | endmethod. 73 | 74 | method get_temp_file_url. 75 | data: separator type c, 76 | guid type guid_32. 77 | 78 | cl_gui_frontend_services=>get_file_separator( 79 | changing 80 | file_separator = separator 81 | exceptions 82 | others = 4 ). 83 | if sy-subrc = 0. 84 | "will not work with local variables... 85 | cl_gui_frontend_services=>get_upload_download_path( 86 | changing 87 | upload_path = uploadpath 88 | download_path = downloadpath 89 | exceptions 90 | others = 6 ). 91 | endif. 92 | if sy-subrc = 0. 93 | call function 'GUID_CREATE' 94 | importing 95 | ev_guid_32 = guid. 96 | 97 | if downloadpath is initial. 98 | 99 | concatenate guid '.html' into r_result. 100 | 101 | else. 102 | 103 | concatenate downloadpath separator guid '.html' into r_result. 104 | 105 | endif. 106 | endif. 107 | 108 | endmethod. 109 | 110 | method popup. 111 | data: ok type abap_bool. 112 | 113 | call function 'POPUP_GET_STRING' 114 | exporting 115 | label = 'Variable name' 116 | importing 117 | value = varname 118 | okay = ok. 119 | 120 | if ok = abap_false. 121 | clear varname. 122 | else. 123 | translate varname to upper case. 124 | endif. 125 | 126 | endmethod. 127 | 128 | endclass. 129 | -------------------------------------------------------------------------------- /zcl_debug_obj_to_graph.clas.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | ZCL_DEBUG_OBJ_TO_GRAPH 7 | 1 8 | E 9 | Convert abap object to graph 10 | 2 11 | 1 12 | X 13 | X 14 | X 15 | X 16 | 17 | 18 | 19 | ZCL_DEBUG_OBJ_TO_GRAPH 20 | C_NEWLINE 21 | E 22 | C_NEWLINE 23 | 24 | 25 | 26 | 27 | 28 | --------------------------------------------------------------------------------