├── src ├── package.devc.xml ├── zui2_data_access.clas.xml ├── zui2_json.clas.locals_imp.abap ├── zjson2abaptype.prog.xml ├── zui2_data_access.clas.testclasses.abap ├── zui2_data_access.clas.abap ├── zui2_json.clas.xml ├── zjson2abaptype.prog.abap └── zui2_json.clas.abap ├── .abapgit.xml ├── README.md ├── .github └── FUNDING.YML └── LICENSE /src/package.devc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JSON Structure 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.abapgit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | E 6 | /src/ 7 | PREFIX 8 | 9 | /.gitignore 10 | /LICENSE 11 | /README.md 12 | /package.json 13 | /.travis.yml 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSON2ABAPType 2 | Creator of ABAP types on a base of JSON structure 3 | 4 | More info on https://abapblog.com/articles/how-to/123-creating-abap-type-definition-from-json-structure and https://blogs.sap.com/2019/10/17/json2abaptype-thank-you-for-contribution/ 5 | 6 | 7 | --- 8 | ![Are you enjoying all the work I do? You can buy me a beer :-)](https://github.com/fidley/falv/assets/7912195/8450c50f-2bfc-4a3b-86cc-c4d8b42ba191) [Are you enjoying all the work I do? You can buy me a beer :-)](https://www.buymeacoffee.com/AbapBlog) 9 | -------------------------------------------------------------------------------- /.github/FUNDING.YML: -------------------------------------------------------------------------------- 1 | github: fidley 2 | patreon: # Replace with a single Patreon username 3 | open_collective: # Replace with a single Open Collective username 4 | ko_fi: # Replace with a single Ko-fi username 5 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 6 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 7 | liberapay: # Replace with a single Liberapay username 8 | issuehunt: # Replace with a single IssueHunt username 9 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 10 | polar: # Replace with a single Polar username 11 | buy_me_a_coffee: abapblog 12 | thanks_dev: # Replace with a single thanks.dev username 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /src/zui2_data_access.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZUI2_DATA_ACCESS 7 | E 8 | Dynamic Data Access Helper Class 9 | 1 10 | X 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | ZUI2_DATA_ACCESS 18 | AT 19 | E 20 | Component accessor 21 | 22 | 23 | ZUI2_DATA_ACCESS 24 | AT_INT 25 | E 26 | Internal helper for comonent access 27 | 28 | 29 | ZUI2_DATA_ACCESS 30 | CONSTRUCTOR 31 | E 32 | Constructor 33 | 34 | 35 | ZUI2_DATA_ACCESS 36 | CREATE 37 | E 38 | Helper method for creating instance of dynamic accessor 39 | 40 | 41 | ZUI2_DATA_ACCESS 42 | DEREF 43 | E 44 | Dereference deep nested references 45 | 46 | 47 | ZUI2_DATA_ACCESS 48 | EMPTY 49 | E 50 | Returns TRUE if embedded object is initial (not bound) 51 | 52 | 53 | ZUI2_DATA_ACCESS 54 | REF 55 | E 56 | Returns reference to embedded object 57 | 58 | 59 | ZUI2_DATA_ACCESS 60 | SET 61 | E 62 | Sets value of the embedded object, if not initial 63 | 64 | 65 | ZUI2_DATA_ACCESS 66 | VALUE 67 | E 68 | Returns copy of the value 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/zui2_json.clas.locals_imp.abap: -------------------------------------------------------------------------------- 1 | *"* local class implementation for public class 2 | *"* use this source file for the implementation part of 3 | *"* local helper classes 4 | 5 | DEFINE escape_json_inplace. 6 | * replace all occurrences of regex `[\\"]` in &1 with `\\$0`. <-- this is slower than 2 plain replaces 7 | replace all occurrences of `\` in &1 with `\\`. 8 | replace all occurrences of `"` in &1 with `\"`. 9 | END-OF-DEFINITION. 10 | 11 | DEFINE escape_json. 12 | move &1 to &2. 13 | escape_json_inplace &2. 14 | END-OF-DEFINITION. 15 | 16 | DEFINE is_compressable. 17 | IF mv_extended IS INITIAL. 18 | &3 = abap_true. 19 | ELSE. 20 | &3 = is_compressable( type_descr = &1 name = &2 ). 21 | ENDIF. 22 | END-OF-DEFINITION. 23 | 24 | DEFINE dump_type. 25 | IF mv_extended IS INITIAL. 26 | dump_type_int &1 &2 &3. 27 | ELSE. 28 | &3 = dump_type( data = &1 type_descr = &2 ). 29 | ENDIF. 30 | END-OF-DEFINITION. 31 | 32 | DEFINE dump_type_int. 33 | 34 | case &2->type_kind. 35 | when cl_abap_typedescr=>typekind_float or cl_abap_typedescr=>typekind_int or cl_abap_typedescr=>typekind_int1 or 36 | cl_abap_typedescr=>typekind_int2 or cl_abap_typedescr=>typekind_packed or `8`. " TYPEKIND_INT8 -> '8' only from 7.40. 37 | if &2->type_kind eq cl_abap_typedescr=>typekind_packed and mv_ts_as_iso8601 eq c_bool-true and &2->absolute_name cp `\TYPE=TIMESTAMP*`. 38 | if &1 is initial. 39 | &3 = `""`. 40 | else. 41 | move &1 to &3. 42 | if &2->absolute_name eq `\TYPE=TIMESTAMP`. 43 | concatenate `"` &3(4) `-` &3+4(2) `-` &3+6(2) `T` &3+8(2) `:` &3+10(2) `:` &3+12(2) `.0000000Z"` into &3. 44 | elseif &2->absolute_name eq `\TYPE=TIMESTAMPL`. 45 | concatenate `"` &3(4) `-` &3+4(2) `-` &3+6(2) `T` &3+8(2) `:` &3+10(2) `:` &3+12(2) `.` &3+15(7) `Z"` into &3. 46 | endif. 47 | endif. 48 | elseif &1 is initial. 49 | &3 = `0`. 50 | else. 51 | move &1 to &3. 52 | if &1 lt 0. 53 | if &2->type_kind <> cl_abap_typedescr=>typekind_float. "float: sign is already at the beginning 54 | shift &3 right circular. 55 | endif. 56 | else. 57 | condense &3. 58 | endif. 59 | endif. 60 | when cl_abap_typedescr=>typekind_num. 61 | if mv_numc_as_string eq abap_true. 62 | if &1 is initial. 63 | &3 = `""`. 64 | else. 65 | concatenate `"` &1 `"` into &3. 66 | endif. 67 | else. 68 | if &1 is initial. 69 | &3 = `0`. 70 | else. 71 | move &1 to &3. 72 | shift &3 left deleting leading ` 0`. 73 | endif. 74 | endif. 75 | when cl_abap_typedescr=>typekind_string or cl_abap_typedescr=>typekind_csequence or cl_abap_typedescr=>typekind_clike. 76 | if &1 is initial. 77 | &3 = `""`. 78 | elseif &2->absolute_name eq mc_json_type. 79 | &3 = &1. 80 | else. 81 | escape_json &1 &3. 82 | concatenate `"` &3 `"` into &3. 83 | endif. 84 | when cl_abap_typedescr=>typekind_xstring or cl_abap_typedescr=>typekind_hex. 85 | if &1 is initial. 86 | &3 = `""`. 87 | else. 88 | &3 = xstring_to_string( &1 ). 89 | escape_json_inplace &3. 90 | concatenate `"` &3 `"` into &3. 91 | endif. 92 | when cl_abap_typedescr=>typekind_char. 93 | if &2->output_length eq 1 and mc_bool_types cs &2->absolute_name. 94 | if &1 eq c_bool-true. 95 | &3 = `true`. "#EC NOTEXT 96 | elseif mc_bool_3state cs &2->absolute_name and &1 is initial. 97 | &3 = `null`. "#EC NOTEXT 98 | else. 99 | &3 = `false`. "#EC NOTEXT 100 | endif. 101 | else. 102 | escape_json &1 &3. 103 | concatenate `"` &3 `"` into &3. 104 | endif. 105 | when cl_abap_typedescr=>typekind_date. 106 | concatenate `"` &1(4) `-` &1+4(2) `-` &1+6(2) `"` into &3. 107 | when cl_abap_typedescr=>typekind_time. 108 | concatenate `"` &1(2) `:` &1+2(2) `:` &1+4(2) `"` into &3. 109 | when others. 110 | if &1 is initial. 111 | &3 = `null`. "#EC NOTEXT 112 | else. 113 | move &1 to &3. 114 | endif. 115 | endcase. 116 | 117 | END-OF-DEFINITION. 118 | 119 | DEFINE format_name. 120 | case &2. 121 | when pretty_mode-camel_case. 122 | &3 = pretty_name( &1 ). 123 | when pretty_mode-extended. 124 | &3 = pretty_name_ex( &1 ). 125 | when pretty_mode-user_low_case. 126 | read table mt_name_mappings with table key abap = &1 assigning . 127 | if sy-subrc is initial. 128 | &3 = -json. 129 | else. 130 | &3 = &1. 131 | translate &3 to lower case. "#EC SYNTCHAR 132 | endif. 133 | when pretty_mode-user. 134 | read table mt_name_mappings with table key abap = &1 assigning . 135 | if sy-subrc is initial. 136 | &3 = -json. 137 | else. 138 | &3 = &1. 139 | endif. 140 | when pretty_mode-low_case. 141 | &3 = &1. 142 | translate &3 to lower case. "#EC SYNTCHAR 143 | when others. 144 | &3 = &1. 145 | endcase. 146 | END-OF-DEFINITION. 147 | 148 | DEFINE throw_error. 149 | raise exception type cx_sy_move_cast_error. 150 | END-OF-DEFINITION. 151 | 152 | DEFINE while_offset_cs. 153 | * >= 7.02 alternative 154 | * pos = find_any_not_of( val = json sub = &1 off = offset ). 155 | * if pos eq -1. offset = length. 156 | * else. offset = pos. endif. 157 | 158 | * < 7.02 159 | while offset < length. 160 | find first occurrence of json+offset(1) in &1. 161 | if sy-subrc is not initial. 162 | exit. 163 | endif. 164 | offset = offset + 1. 165 | endwhile. 166 | * < 7.02 167 | 168 | END-OF-DEFINITION. 169 | 170 | 171 | DEFINE eat_white. 172 | while_offset_cs sv_white_space. 173 | END-OF-DEFINITION. 174 | 175 | DEFINE eat_string. 176 | if json+offset(1) eq `"`. 177 | mark = offset + 1. 178 | offset = mark. 179 | do. 180 | find first occurrence of `"` in section offset offset of json match offset pos. 181 | if sy-subrc is not initial. 182 | throw_error. 183 | endif. 184 | offset = pos. 185 | pos = pos - 1. 186 | " if escaped search further 187 | while pos ge 0 and json+pos(1) eq `\`. 188 | pos = pos - 1. 189 | endwhile. 190 | match = ( offset - pos ) mod 2. 191 | if match ne 0. 192 | exit. 193 | endif. 194 | offset = offset + 1. 195 | enddo. 196 | match = offset - mark. 197 | &1 = json+mark(match). 198 | " unescaped singe characters, e.g \\, \", \/ etc 199 | replace all occurrences of regex `\\(.)` in &1 with `$1`. 200 | offset = offset + 1. 201 | else. 202 | throw_error. 203 | endif. 204 | END-OF-DEFINITION. 205 | 206 | DEFINE eat_number. 207 | mark = offset. 208 | while_offset_cs `0123456789+-eE.`. "#EC NOTEXT 209 | match = offset - mark. 210 | &1 = json+mark(match). 211 | END-OF-DEFINITION. 212 | 213 | DEFINE eat_bool. 214 | mark = offset. 215 | while_offset_cs `aeflnrstu`. "#EC NOTEXT 216 | match = offset - mark. 217 | if json+mark(match) eq `true`. "#EC NOTEXT 218 | &1 = c_bool-true. 219 | elseif json+mark(match) eq `false`. "#EC NOTEXT 220 | if type_descr is bound and mc_bool_3state cs type_descr->absolute_name. 221 | &1 = c_tribool-false. 222 | else. 223 | &1 = c_bool-false. 224 | endif. 225 | elseif json+mark(match) eq `null`. "#EC NOTEXT 226 | clear &1. 227 | endif. 228 | END-OF-DEFINITION. 229 | 230 | DEFINE eat_char. 231 | if offset < length and json+offset(1) eq &1. 232 | offset = offset + 1. 233 | else. 234 | throw_error. 235 | endif. 236 | END-OF-DEFINITION. 237 | -------------------------------------------------------------------------------- /src/zjson2abaptype.prog.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZJSON2ABAPTYPE 7 | 1 8 | K 9 | E 10 | X 11 | X 12 | 13 | 14 | 15 |
16 | ZJSON2ABAPTYPE 17 | 0100 18 | E 19 | Main screen 20 | N 21 | 0100 22 | 200 23 | 255 24 |
25 | 26 | 27 | SCREEN 28 | SCREEN 29 | 30 | 31 | SUBSCREEN 32 | SUB1 33 | SCREEN 34 | 001 35 | 001 36 | 123 37 | 006 38 | 39 | 40 | CUST_CTRL 41 | CC_INPUT 42 | SCREEN 43 | 008 44 | 001 45 | 254 46 | 158 47 | X 48 | X 49 | 010 50 | 010 51 | 52 | 53 | 54 | 55 | SCREEN 56 | SCREEN 57 | OKCODE 58 | OK_CODE 59 | ____________________ 60 | 020 61 | 020 62 | 001 63 | CHAR 64 | X 65 | 66 | 67 | 68 | 69 | PROCESS BEFORE OUTPUT. 70 | 71 | 72 | MODULE pbo. 73 | 74 | 75 | CALL SUBSCREEN sub1 INCLUDING sy-repid '1001'. 76 | 77 | 78 | 79 | PROCESS AFTER INPUT. 80 | 81 | 82 | CALL SUBSCREEN sub1 . 83 | 84 | 85 | MODULE pai. 86 | 87 | 88 |
89 |
90 | 91 | 92 | 000001 93 | 000001 94 | 95 | 96 | 97 | STATUS_0100 98 | D 99 | 000001 100 | 000001 101 | 0001 102 | STATUS 103 | 104 | 105 | 106 | 107 | BACK 108 | 001 109 | S 110 | Back 111 | 112 | 113 | CODE_CONV 114 | 001 115 | S 116 | ICON_CONVERT_ALL 117 | @BV@ 118 | Convert 119 | 120 | 121 | CONVERT 122 | 001 123 | S 124 | ICON_CONVERT_ALL 125 | @BV@ 126 | Convert 127 | Convert 128 | 129 | 130 | EXIT 131 | 001 132 | S 133 | ICON_CANCEL 134 | @0W@ 135 | Cancel 136 | 137 | 138 | UP 139 | 001 140 | S 141 | Exit 142 | 143 | 144 | 145 | 146 | 000001 147 | 0001 148 | 01 149 | 08 150 | 151 | 152 | 153 | 154 | 000001 155 | 03 156 | BACK 157 | 001 158 | 159 | 160 | 000001 161 | 08 162 | CONVERT 163 | 001 164 | 165 | 166 | 000001 167 | 09 168 | CODE_CONV 169 | 001 170 | 171 | 172 | 000001 173 | 12 174 | EXIT 175 | 001 176 | 177 | 178 | 000001 179 | 15 180 | UP 181 | 001 182 | 183 | 184 | 185 | 186 | STATUS_0100 187 | BACK 188 | 189 | 190 | STATUS_0100 191 | CODE_CONV 192 | 193 | 194 | STATUS_0100 195 | CONVERT 196 | 197 | 198 | STATUS_0100 199 | EXIT 200 | 201 | 202 | STATUS_0100 203 | UP 204 | 205 | 206 | 207 | 208 | A 209 | 000001 210 | D 211 | STATUS 212 | 213 | 214 | P 215 | 000001 216 | D 217 | STATUS 218 | 219 | 220 | B 221 | 000001 222 | 0001 223 | D 224 | STATUS 225 | 226 | 227 | 228 | 229 | TITLE 230 | JSON2ABAPType 231 | 232 | 233 | 234 | 235 | 236 | R 237 | ZJSONSTRUCTURE 238 | 14 239 | 240 | 241 | S 242 | P_CAMEL 243 | Camel Case 244 | 18 245 | 246 | 247 | S 248 | P_CASES 249 | Case Sensitive 250 | 22 251 | 252 | 253 | S 254 | P_EXT 255 | Extended 256 | 16 257 | 258 | 259 | S 260 | P_LOW 261 | Lower Case 262 | 18 263 | 264 | 265 | S 266 | P_NONE 267 | None 268 | 12 269 | 270 | 271 | S 272 | P_USER 273 | User 274 | 12 275 | 276 | 277 | S 278 | P_USERLO 279 | User Lower Case 280 | 23 281 | 282 | 283 |
284 |
285 |
286 | -------------------------------------------------------------------------------- /src/zui2_data_access.clas.testclasses.abap: -------------------------------------------------------------------------------- 1 | *"* use this source file for your ABAP unit test classes 2 | CLASS lc_ut DEFINITION FOR TESTING FINAL "#AU Duration Medium 3 | "#AU Risk_Level Harmless 4 | . 5 | 6 | PUBLIC SECTION. 7 | TYPES: 8 | BEGIN OF t_properties, 9 | enabled TYPE abap_bool, 10 | length TYPE i, 11 | description TYPE c LENGTH 20, 12 | END OF t_properties, 13 | BEGIN OF t_data, 14 | id TYPE i, 15 | properties TYPE t_properties, 16 | content TYPE string, 17 | END OF t_data, 18 | BEGIN OF t_name_value, 19 | name TYPE string, 20 | value TYPE string, 21 | END OF t_name_value, 22 | BEGIN OF t_example, 23 | flag TYPE abap_bool, 24 | props TYPE t_data, 25 | params TYPE SORTED TABLE OF t_name_value WITH UNIQUE KEY name, 26 | params2 TYPE SORTED TABLE OF t_name_value WITH UNIQUE KEY name value, 27 | END OF t_example. 28 | 29 | METHODS: test_basic_actions FOR TESTING. 30 | METHODS: test_table_access FOR TESTING. 31 | 32 | ENDCLASS. "lc_ut 33 | 34 | 35 | CLASS lc_ut IMPLEMENTATION. 36 | 37 | METHOD test_basic_actions. 38 | 39 | DATA: ls_data TYPE t_example, 40 | lr_data TYPE REF TO data, 41 | lr_ref TYPE REF TO data, 42 | lv_int TYPE i, 43 | lo_data TYPE REF TO ZUI2_DATA_ACCESS, 44 | lo_tmp LIKE lo_data. 45 | 46 | FIELD-SYMBOLS: TYPE data. 47 | 48 | ls_data-props-id = 12345. 49 | ls_data-props-content = `Some Content`. 50 | ls_data-props-properties-enabled = abap_false. 51 | ls_data-props-properties-length = 10. 52 | ls_data-props-properties-description = `My description`. 53 | 54 | GET REFERENCE OF ls_data INTO lr_data. 55 | 56 | CREATE OBJECT lo_data EXPORTING ir_data = lr_data. 57 | 58 | " standard way (does not work on SAP_BASIS 700) 59 | lo_tmp = lo_data->at(`PROPS`). 60 | lo_tmp = lo_tmp->at(`id`). 61 | lr_ref = lo_tmp->ref( ). 62 | " lr_ref = lo_data->at(`PROPS`)->at(`id`)->ref( ). => 700 63 | cl_aunit_assert=>assert_bound( act = lr_ref msg = `Dynamic access to existing property fails!` ). 64 | 65 | ASSIGN lr_ref->* TO . 66 | cl_aunit_assert=>assert_equals( act = exp = ls_data-props-id msg = `Dynamic access to existing property fails!` ). 67 | 68 | lo_tmp = lo_data->at(`PROPS`). 69 | lo_tmp = lo_tmp->at(`key`). 70 | lr_ref = lo_tmp->ref( ). 71 | " lr_ref = lo_data->at(`PROPS`)->at(`key`)->ref( ). => 700 72 | cl_aunit_assert=>assert_not_bound( act = lr_ref msg = `Dynamic access to NOT existing property fails!` ). 73 | 74 | " XPath like 75 | lo_tmp = lo_data->at(`PROPS-ID`). 76 | lr_ref = lo_tmp->ref( ). 77 | " lr_ref = lo_data->at(`PROPS-ID`)->ref( ). => 700 78 | cl_aunit_assert=>assert_bound( act = lr_ref msg = `Dynamic access to existing property fails!` ). 79 | 80 | ASSIGN lr_ref->* TO . 81 | cl_aunit_assert=>assert_equals( act = exp = ls_data-props-id msg = `Dynamic access to existing property fails!` ). 82 | 83 | " Alternative component separator 84 | lo_tmp = lo_data->at(`PROPS->ID`). 85 | lr_ref = lo_tmp->ref( ). 86 | " lr_ref = lo_data->at(`PROPS->ID`)->ref( ). => 700 87 | cl_aunit_assert=>assert_bound( act = lr_ref msg = `Dynamic access to existing property fails!` ). 88 | 89 | ASSIGN lr_ref->* TO . 90 | cl_aunit_assert=>assert_equals( act = exp = ls_data-props-id msg = `Dynamic access to existing property fails!` ). 91 | 92 | " using helper method for creation 93 | lo_tmp = ZUI2_DATA_ACCESS=>create( ir_data = lr_data iv_component = `PROPS-ID`). 94 | lr_ref = lo_tmp->ref( ). 95 | " lr_ref = ZUI2_DATA_ACCESS=>create( ir_data = lr_data iv_component = `PROPS-ID`)->ref( ). => 700 96 | cl_aunit_assert=>assert_bound( act = lr_ref msg = `Dynamic access to existing property fails!` ). 97 | 98 | ASSIGN lr_ref->* TO . 99 | cl_aunit_assert=>assert_equals( act = exp = ls_data-props-id msg = `Dynamic access to existing property fails!` ). 100 | 101 | " reading value 102 | lo_tmp = lo_data->at(`props-properties-length`). 103 | lo_tmp->value( IMPORTING ev_data = lv_int ). 104 | " lo_data->at(`props-properties-length`)->value( IMPORTING ev_data = lv_int ). => 700 105 | cl_aunit_assert=>assert_equals( act = lv_int exp = ls_data-props-properties-length msg = `Dynamic read of existing the property fails!` ). 106 | 107 | lv_int = 25. 108 | lo_tmp = lo_data->at(`props-properties-len`). 109 | lo_tmp->value( IMPORTING ev_data = lv_int ). 110 | " lo_data->at(`props-properties-len`)->value( IMPORTING ev_data = lv_int ). => 700 111 | cl_aunit_assert=>assert_initial( act = lv_int msg = `Dynamic read of the NOT existing property fails!` ). 112 | 113 | " modifing value 114 | lv_int = 25. 115 | lo_tmp = lo_data->at(`props-properties-length`). 116 | lr_ref = lo_tmp->ref( ). 117 | " lr_ref = lo_data->at(`props-properties-length`)->ref( ). => 700 118 | ASSIGN lr_ref->* TO . 119 | = lv_int. 120 | cl_aunit_assert=>assert_equals( act = lv_int exp = ls_data-props-properties-length msg = `Dynamic modification of the existing property fails!` ). 121 | 122 | lv_int = 15. 123 | lo_tmp = lo_data->at(`props-properties-length`). 124 | lo_tmp->set( lv_int ). 125 | " lo_data->at(`props-properties-length`)->set( lv_int ). => 700 126 | cl_aunit_assert=>assert_equals( act = lv_int exp = ls_data-props-properties-length msg = `Dynamic modification of the existing property fails!` ). 127 | 128 | " degenerated example 129 | lv_int = 15. 130 | lo_tmp = ZUI2_DATA_ACCESS=>create( iv_data = lv_int ). 131 | lr_ref = lo_tmp->ref( ). 132 | " lr_ref = ZUI2_DATA_ACCESS=>create( iv_data = lv_int )->ref( ). => 700 133 | ASSIGN lr_ref->* TO . 134 | cl_aunit_assert=>assert_equals( act = exp = lv_int msg = `Dynamic access of existing the property fails!` ). 135 | 136 | ENDMETHOD. 137 | 138 | METHOD test_table_access. 139 | 140 | DATA: 141 | ls_data TYPE t_example, 142 | ls_line LIKE LINE OF ls_data-params, 143 | lv_value TYPE string, 144 | lo_data TYPE REF TO ZUI2_DATA_ACCESS. 145 | 146 | ls_line-name = `KEY1`. 147 | ls_line-value = `Value1`. 148 | INSERT ls_line INTO TABLE ls_data-params. 149 | INSERT ls_line INTO TABLE ls_data-params2. 150 | 151 | ls_line-name = `KEY2`. 152 | ls_line-value = `Value1`. 153 | INSERT ls_line INTO TABLE ls_data-params. 154 | INSERT ls_line INTO TABLE ls_data-params2. 155 | 156 | ls_line-name = `KEY2`. 157 | ls_line-value = `Value2`. 158 | INSERT ls_line INTO TABLE ls_data-params. 159 | INSERT ls_line INTO TABLE ls_data-params2. 160 | 161 | ls_line-name = `KEY3`. 162 | ls_line-value = `Value1, Value2`. 163 | INSERT ls_line INTO TABLE ls_data-params. 164 | INSERT ls_line INTO TABLE ls_data-params2. 165 | 166 | lo_data = ZUI2_DATA_ACCESS=>create( iv_data = ls_data iv_component = `params[2]-name`). 167 | lo_data->value( IMPORTING ev_data = lv_value ). 168 | 169 | cl_aunit_assert=>assert_equals( act = lv_value exp = `KEY2` msg = `Dynamic read to table item by index fails!` ). 170 | 171 | lo_data = ZUI2_DATA_ACCESS=>create( iv_data = ls_data iv_component = `params[name=KEY1]-value`). 172 | lo_data->value( IMPORTING ev_data = lv_value ). 173 | 174 | cl_aunit_assert=>assert_equals( act = lv_value exp = `Value1` msg = `Dynamic read to table item by key index fails!` ). 175 | 176 | lo_data = ZUI2_DATA_ACCESS=>create( iv_data = ls_data iv_component = `params`). 177 | lo_data = lo_data->at(`[name=KEY1]-value`). 178 | lo_data->value( IMPORTING ev_data = lv_value ). 179 | 180 | cl_aunit_assert=>assert_equals( act = lv_value exp = `Value1` msg = `Dynamic read to table item by key index fails!` ). 181 | 182 | lo_data = ZUI2_DATA_ACCESS=>create( iv_data = ls_data iv_component = `params2[name=KEY2, value=Value2]-value`). 183 | lo_data->value( IMPORTING ev_data = lv_value ). 184 | 185 | cl_aunit_assert=>assert_equals( act = lv_value exp = `Value2` msg = `Dynamic read to table item by key index fails!` ). 186 | 187 | " we do not support usage usage of "," or "]" as part of the key :( 188 | lo_data = ZUI2_DATA_ACCESS=>create( iv_data = ls_data iv_component = `params2[name=KEY3, value=Value1, Value2]-value`). 189 | lo_data->value( IMPORTING ev_data = lv_value ). 190 | 191 | cl_aunit_assert=>assert_equals( act = lv_value exp = `` msg = `Dynamic read to table item by unescaped key works!` ). 192 | 193 | ENDMETHOD. 194 | 195 | ENDCLASS. 196 | -------------------------------------------------------------------------------- /src/zui2_data_access.clas.abap: -------------------------------------------------------------------------------- 1 | CLASS zui2_data_access DEFINITION 2 | PUBLIC 3 | CREATE PUBLIC . 4 | 5 | PUBLIC SECTION. 6 | TYPE-POOLS abap . 7 | 8 | CLASS-METHODS create 9 | IMPORTING 10 | !ir_data TYPE REF TO data OPTIONAL 11 | !iv_data TYPE data OPTIONAL 12 | !iv_component TYPE string OPTIONAL 13 | RETURNING 14 | VALUE(ro_ref) TYPE REF TO zui2_data_access . 15 | METHODS constructor 16 | IMPORTING 17 | !ir_data TYPE REF TO data OPTIONAL 18 | !iv_data TYPE data OPTIONAL . 19 | METHODS at 20 | IMPORTING 21 | !iv_component TYPE string OPTIONAL 22 | RETURNING 23 | VALUE(ro_ref) TYPE REF TO zui2_data_access . 24 | METHODS empty 25 | RETURNING 26 | VALUE(rv_val) TYPE abap_bool . 27 | METHODS ref 28 | RETURNING 29 | VALUE(rv_data) TYPE REF TO data . 30 | METHODS value 31 | IMPORTING 32 | !iv_default TYPE data OPTIONAL 33 | EXPORTING 34 | !ev_data TYPE data . 35 | METHODS set 36 | IMPORTING 37 | !iv_data TYPE data 38 | RETURNING 39 | VALUE(rv_success) TYPE abap_bool . 40 | PROTECTED SECTION. 41 | 42 | DATA mr_data TYPE REF TO data . 43 | 44 | CLASS-METHODS deref 45 | IMPORTING 46 | !ir_data TYPE REF TO data 47 | RETURNING 48 | VALUE(rr_data) TYPE REF TO data . 49 | METHODS at_int 50 | IMPORTING 51 | !iv_component TYPE string OPTIONAL 52 | !iv_index TYPE i OPTIONAL 53 | !iv_keys TYPE string OPTIONAL 54 | RETURNING 55 | VALUE(ro_ref) TYPE REF TO zui2_data_access . 56 | PRIVATE SECTION. 57 | ENDCLASS. 58 | 59 | 60 | 61 | CLASS ZUI2_DATA_ACCESS IMPLEMENTATION. 62 | 63 | 64 | METHOD at. 65 | 66 | DATA: 67 | lv_component TYPE string, 68 | lv_sindex TYPE string, 69 | lv_keys TYPE string, 70 | lv_index TYPE i, 71 | lt_hier TYPE match_result_tab. 72 | 73 | FIELD-SYMBOLS: 74 | LIKE LINE OF lt_hier, 75 | TYPE LINE OF submatch_result_tab. 76 | 77 | " (?:(\w+)|^)(?:\[(?:(\d+)|([^\]]+))\])? - no check for separators 78 | FIND ALL OCCURRENCES OF REGEX `(?:(\w+)|^)(?:\[(?:(\d+)|([^\]]+))\])?(?:(?:-\>)|(?:-)|(?:=>)|$)` IN iv_component RESULTS lt_hier. 79 | 80 | ro_ref = me. 81 | 82 | LOOP AT lt_hier ASSIGNING . 83 | CHECK ro_ref->empty( ) EQ abap_false. 84 | READ TABLE -submatches INDEX 1 ASSIGNING . 85 | IF -length IS INITIAL. 86 | CLEAR lv_component. 87 | ELSE. 88 | lv_component = iv_component+-offset(-length). 89 | TRANSLATE lv_component TO UPPER CASE. 90 | ENDIF. 91 | READ TABLE -submatches INDEX 2 ASSIGNING . 92 | IF -length IS INITIAL. 93 | CLEAR lv_index. 94 | ELSE. 95 | lv_index = lv_sindex = iv_component+-offset(-length). 96 | ENDIF. 97 | READ TABLE -submatches INDEX 3 ASSIGNING . 98 | IF -length IS INITIAL. 99 | CLEAR lv_keys. 100 | ELSE. 101 | lv_keys = iv_component+-offset(-length). 102 | ENDIF. 103 | ro_ref = ro_ref->at_int( iv_component = lv_component iv_index = lv_index iv_keys = lv_keys ). 104 | ENDLOOP. 105 | 106 | ENDMETHOD. "at_int 107 | 108 | 109 | METHOD at_int. 110 | 111 | DATA: lv_key TYPE string, 112 | lv_value TYPE string, 113 | lt_keys TYPE match_result_tab, 114 | lr_data TYPE REF TO data, 115 | lo_type TYPE REF TO cl_abap_typedescr. 116 | 117 | FIELD-SYMBOLS: TYPE data, 118 | TYPE data, 119 | LIKE LINE OF lt_keys, 120 | TYPE LINE OF submatch_result_tab, 121 | TYPE REF TO data, 122 | TYPE ANY TABLE, 123 | TYPE INDEX TABLE. 124 | 125 | IF mr_data IS BOUND. 126 | IF iv_component IS NOT INITIAL. 127 | ASSIGN mr_data->* TO . 128 | ASSIGN COMPONENT iv_component OF STRUCTURE TO . 129 | IF IS ASSIGNED. 130 | GET REFERENCE OF INTO lr_data. 131 | lr_data = deref( lr_data ). 132 | ASSIGN lr_data TO . 133 | ENDIF. 134 | ELSE. 135 | ASSIGN mr_data TO . 136 | ENDIF. 137 | ENDIF. 138 | 139 | IF IS ASSIGNED AND ( iv_index IS NOT INITIAL OR iv_keys IS NOT INITIAL ). 140 | lo_type = cl_abap_typedescr=>describe_by_data_ref( ). 141 | IF lo_type->kind EQ cl_abap_typedescr=>kind_table. 142 | " check for table index access 143 | IF iv_index IS NOT INITIAL. 144 | ASSIGN ->* TO . 145 | IF sy-subrc IS INITIAL. 146 | READ TABLE INDEX iv_index REFERENCE INTO . 147 | IF sy-subrc IS NOT INITIAL. 148 | UNASSIGN . 149 | ENDIF. 150 | ELSE. 151 | UNASSIGN . 152 | ENDIF. 153 | ELSEIF iv_keys IS NOT INITIAL. 154 | ASSIGN ->* TO
. 155 | IF sy-subrc IS INITIAL. 156 | CREATE DATA lr_data LIKE LINE OF
. 157 | ASSIGN lr_data->* TO . 158 | FIND ALL OCCURRENCES OF REGEX `(\w+)\s*=\s*([^,]*),?` IN iv_keys RESULTS lt_keys. 159 | IF sy-subrc IS INITIAL. 160 | LOOP AT lt_keys ASSIGNING . 161 | READ TABLE -submatches INDEX 1 ASSIGNING . 162 | lv_key = iv_keys+-offset(-length). 163 | TRANSLATE lv_key TO UPPER CASE. 164 | READ TABLE -submatches INDEX 2 ASSIGNING . 165 | lv_value = iv_keys+-offset(-length). 166 | ASSIGN COMPONENT lv_key OF STRUCTURE TO . 167 | CHECK sy-subrc IS INITIAL. 168 | = lv_value. 169 | ENDLOOP. 170 | ELSE. 171 | = lv_key. 172 | ENDIF. 173 | READ TABLE
FROM REFERENCE INTO . 174 | IF sy-subrc IS NOT INITIAL. 175 | UNASSIGN . 176 | ENDIF. 177 | ELSE. 178 | UNASSIGN . 179 | ENDIF. 180 | ENDIF. 181 | ENDIF. 182 | ENDIF. 183 | 184 | IF IS ASSIGNED. 185 | CREATE OBJECT ro_ref 186 | EXPORTING 187 | ir_data = . 188 | ELSE. 189 | CREATE OBJECT ro_ref. 190 | ENDIF. 191 | 192 | ENDMETHOD. "at_int 193 | 194 | 195 | METHOD constructor. 196 | IF ir_data IS NOT INITIAL. 197 | mr_data = ir_data. 198 | ELSEIF iv_data IS SUPPLIED. 199 | GET REFERENCE OF iv_data INTO mr_data. 200 | ENDIF. 201 | mr_data = deref( mr_data ). 202 | ENDMETHOD. "constructor 203 | 204 | 205 | METHOD create. 206 | IF iv_data IS SUPPLIED. 207 | CREATE OBJECT ro_ref 208 | EXPORTING 209 | iv_data = iv_data. 210 | ELSE. 211 | CREATE OBJECT ro_ref 212 | EXPORTING 213 | ir_data = ir_data. 214 | ENDIF. 215 | 216 | IF iv_component IS NOT INITIAL. 217 | ro_ref = ro_ref->at( iv_component ). 218 | ENDIF. 219 | ENDMETHOD. "create 220 | 221 | 222 | METHOD deref. 223 | 224 | DATA: lo_type TYPE REF TO cl_abap_typedescr. 225 | 226 | FIELD-SYMBOLS: TYPE data. 227 | 228 | rr_data = ir_data. 229 | IF rr_data IS NOT INITIAL. 230 | lo_type = cl_abap_typedescr=>describe_by_data_ref( ir_data ). 231 | IF lo_type->kind EQ cl_abap_typedescr=>kind_ref. 232 | ASSIGN ir_data->* TO . 233 | rr_data = deref( ). 234 | ENDIF. 235 | ENDIF. 236 | 237 | ENDMETHOD. "deref 238 | 239 | 240 | METHOD empty. 241 | IF mr_data IS INITIAL. 242 | rv_val = abap_true. 243 | ENDIF. 244 | ENDMETHOD. "empty 245 | 246 | 247 | METHOD ref. 248 | rv_data = mr_data. 249 | ENDMETHOD. "ref 250 | 251 | 252 | METHOD set. 253 | 254 | FIELD-SYMBOLS: TYPE data. 255 | 256 | IF mr_data IS BOUND. 257 | ASSIGN mr_data->* TO . 258 | = iv_data. 259 | rv_success = abap_true. 260 | ENDIF. 261 | 262 | ENDMETHOD. 263 | 264 | 265 | METHOD value. 266 | 267 | DATA: lo_type_out TYPE REF TO cl_abap_typedescr, 268 | lo_type_in TYPE REF TO cl_abap_typedescr. 269 | 270 | FIELD-SYMBOLS: TYPE data. 271 | 272 | CLEAR ev_data. 273 | 274 | IF mr_data IS BOUND. 275 | ASSIGN mr_data->* TO . 276 | lo_type_out = cl_abap_typedescr=>describe_by_data( ev_data ). 277 | lo_type_in = cl_abap_typedescr=>describe_by_data( ). 278 | IF lo_type_out->kind EQ lo_type_in->kind. 279 | ev_data = . 280 | ENDIF. 281 | ELSEIF iv_default IS SUPPLIED. 282 | ev_data = iv_default. 283 | ENDIF. 284 | 285 | ENDMETHOD. "value 286 | ENDCLASS. 287 | -------------------------------------------------------------------------------- /src/zui2_json.clas.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ZUI2_JSON 7 | E 8 | JSON converter 9 | 1 10 | X 11 | X 12 | X 13 | X 14 | 15 | 16 | 17 | ZUI2_JSON 18 | BOOL 19 | E 20 | 2 state boolean type ('X' - true, '' - false), as abap_bool 21 | 22 | 23 | ZUI2_JSON 24 | BOOL_TO_TRIBOOL 25 | E 26 | Convertes 2 state bool to 3 state bool 27 | 28 | 29 | ZUI2_JSON 30 | CLASS_CONSTRUCTOR 31 | E 32 | CLASS_CONSTRUCTOR 33 | 34 | 35 | ZUI2_JSON 36 | CONSTRUCTOR 37 | E 38 | CONSTRUCTOR 39 | 40 | 41 | ZUI2_JSON 42 | DESERIALIZE 43 | E 44 | Serializes object 45 | 46 | 47 | ZUI2_JSON 48 | DESERIALIZE_INT 49 | E 50 | Deserializes ABAP object from JSON 51 | 52 | 53 | ZUI2_JSON 54 | DUMP 55 | E 56 | Recursive conversion 57 | 58 | 59 | ZUI2_JSON 60 | DUMP_INT 61 | E 62 | Recursive conversion 63 | 64 | 65 | ZUI2_JSON 66 | DUMP_SYMBOLS 67 | E 68 | Dump to JSON symbol table 69 | 70 | 71 | ZUI2_JSON 72 | DUMP_TYPE 73 | E 74 | Dumps elementary type to string 75 | 76 | 77 | ZUI2_JSON 78 | DUMP_TYPE_EX 79 | E 80 | Dumps elementary type to string (no type description needed) 81 | 82 | 83 | ZUI2_JSON 84 | ESCAPE 85 | E 86 | Escapes JSON String 87 | 88 | 89 | ZUI2_JSON 90 | GENERATE 91 | E 92 | Generates ABAP object from JSON 93 | 94 | 95 | ZUI2_JSON 96 | GENERATE_INT 97 | E 98 | Generates ABAP object from JSON 99 | 100 | 101 | ZUI2_JSON 102 | GENERATE_INT_EX 103 | E 104 | Generates ABAP object from JSON 105 | 106 | 107 | ZUI2_JSON 108 | GET_FIELDS 109 | E 110 | Prepares structure fields cache 111 | 112 | 113 | ZUI2_JSON 114 | GET_SYMBOLS 115 | E 116 | Alternative impl. of CL_ABAP_STRUCTDESCR=>GET_SYMBOLS_TAB 117 | 118 | 119 | ZUI2_JSON 120 | IS_COMPRESSABLE 121 | E 122 | Check if initial field shall be compressed 123 | 124 | 125 | ZUI2_JSON 126 | JSON 127 | E 128 | JSON string 129 | 130 | 131 | ZUI2_JSON 132 | MC_JSON_TYPE 133 | E 134 | Absolute name of JSON string type 135 | 136 | 137 | ZUI2_JSON 138 | MC_KEY_SEPARATOR 139 | E 140 | Separator inserted between parts of compound keys 141 | 142 | 143 | ZUI2_JSON 144 | MC_ME_TYPE 145 | E 146 | The class name 147 | 148 | 149 | ZUI2_JSON 150 | MV_ASSOC_ARRAYS 151 | E 152 | Serialize tables with unique keys as associative array 153 | 154 | 155 | ZUI2_JSON 156 | MV_ASSOC_ARRAYS_OPT 157 | E 158 | Optimize rendering of name value maps 159 | 160 | 161 | ZUI2_JSON 162 | MV_EXPAND_INCLUDES 163 | E 164 | Expand named includes in structures 165 | 166 | 167 | ZUI2_JSON 168 | MV_EXTENDED 169 | E 170 | The class is used as based class 171 | 172 | 173 | ZUI2_JSON 174 | MV_NUMC_AS_STRING 175 | E 176 | Dump NUMC fields as strings 177 | 178 | 179 | ZUI2_JSON 180 | MV_STRICT_MODE 181 | E 182 | Stop further processing on error 183 | 184 | 185 | ZUI2_JSON 186 | MV_TS_AS_ISO8601 187 | E 188 | Dump timestamps as string in ISO8601 format 189 | 190 | 191 | ZUI2_JSON 192 | NAME_MAPPING 193 | E 194 | ABAP<->JSON Name Mapping 195 | 196 | 197 | ZUI2_JSON 198 | NAME_MAPPINGS 199 | E 200 | ABAP<->JSON Name Mapping Table 201 | 202 | 203 | ZUI2_JSON 204 | PRETTY_NAME 205 | E 206 | PrettyPrint names 207 | 208 | 209 | ZUI2_JSON 210 | PRETTY_NAME_EX 211 | E 212 | PrettyPrint names in extended form 213 | 214 | 215 | ZUI2_JSON 216 | PRETTY_NAME_MODE 217 | E 218 | Name conversion mode 219 | 220 | 221 | ZUI2_JSON 222 | RAW_TO_STRING 223 | E 224 | Converts XSTRING to STRING 225 | 226 | 227 | ZUI2_JSON 228 | RESTORE 229 | E 230 | Deserialize JSON to ABAP 231 | 232 | 233 | ZUI2_JSON 234 | RESTORE_TYPE 235 | E 236 | Deserialize JSON to ABAP 237 | 238 | 239 | ZUI2_JSON 240 | SERIALIZE 241 | E 242 | Serializes object 243 | 244 | 245 | ZUI2_JSON 246 | SERIALIZE_INT 247 | E 248 | Serializes ABAP object to JSON 249 | 250 | 251 | ZUI2_JSON 252 | STRING_TO_RAW 253 | E 254 | Converts STRING to XSTRING 255 | 256 | 257 | ZUI2_JSON 258 | STRING_TO_XSTRING 259 | E 260 | Converts XSTRING data to STRING 261 | 262 | 263 | ZUI2_JSON 264 | SV_WHITE_SPACE 265 | E 266 | White space characters 267 | 268 | 269 | ZUI2_JSON 270 | TRIBOOL 271 | E 272 | 3 state boolean type ('X'-true, '-'-false, ''-undefined) 273 | 274 | 275 | ZUI2_JSON 276 | TRIBOOL_TO_BOOL 277 | E 278 | Convertes 3 state bool to 2 state bool 279 | 280 | 281 | ZUI2_JSON 282 | T_S_SYMBOL 283 | E 284 | Helper type for structure fields iteration 285 | 286 | 287 | ZUI2_JSON 288 | T_T_SYMBOL 289 | E 290 | Standard table of T_S_SYMBOL 291 | 292 | 293 | ZUI2_JSON 294 | VERSION 295 | E 296 | Version of the parser logic 297 | 298 | 299 | ZUI2_JSON 300 | XSTRING_TO_STRING 301 | E 302 | Converts XSTRING data to STRING 303 | 304 | 305 | 306 | 307 | 308 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/zjson2abaptype.prog.abap: -------------------------------------------------------------------------------- 1 | "! This is demo for converting JSON structure into 2 | "! ABAP type 3 | "! done by Lukasz Pegiel for http://abapblog.com 4 | 5 | REPORT zjson2abaptype. 6 | DATA: ok_code TYPE sy-ucomm. 7 | 8 | 9 | SELECTION-SCREEN BEGIN OF SCREEN 1001 AS SUBSCREEN. 10 | 11 | PARAMETERS: p_none RADIOBUTTON GROUP gr1, 12 | p_low RADIOBUTTON GROUP gr1, 13 | p_camel RADIOBUTTON GROUP gr1, 14 | p_ext RADIOBUTTON GROUP gr1 DEFAULT 'X', 15 | p_user RADIOBUTTON GROUP gr1, 16 | p_userlo RADIOBUTTON GROUP gr1, 17 | p_cases RADIOBUTTON GROUP gr1. 18 | 19 | SELECTION-SCREEN END OF SCREEN 1001. 20 | 21 | CLASS lcl_json_structure DEFINITION DEFERRED. 22 | CLASS lcl_hlp DEFINITION. 23 | PUBLIC SECTION. 24 | TYPES: BEGIN OF t_source, 25 | line TYPE char255, 26 | END OF t_source. 27 | TYPES: tt_source TYPE STANDARD TABLE OF t_source WITH DEFAULT KEY. 28 | DATA: converter TYPE REF TO lcl_json_structure, 29 | results TYPE string, 30 | source_editor TYPE REF TO cl_gui_textedit, 31 | abap_editor TYPE REF TO cl_gui_abapedit. 32 | METHODS: constructor. 33 | METHODS: create_source_editor. 34 | METHODS: convert. 35 | METHODS: pai IMPORTING VALUE(i_okcode) TYPE sy-ucomm. 36 | 37 | PRIVATE SECTION. 38 | 39 | METHODS call_editor 40 | CHANGING 41 | c_source TYPE tt_source OPTIONAL. 42 | METHODS pretty_print_code 43 | CHANGING 44 | c_source TYPE tt_source. 45 | METHODS get_pretty_name_mode RETURNING VALUE(pretty_name_mode) TYPE char1. 46 | DATA: handler TYPE REF TO cl_wb_editor. 47 | 48 | ENDCLASS. 49 | 50 | CLASS lcl_json_structure DEFINITION. 51 | 52 | PUBLIC SECTION. 53 | 54 | TYPES: BEGIN OF t_hierarchy, 55 | level TYPE i, 56 | name TYPE string, 57 | table TYPE abap_bool, 58 | structure TYPE abap_bool, 59 | type TYPE string, 60 | length TYPE i, 61 | decimals TYPE i, 62 | absolute_type TYPE abap_abstypename, 63 | parent TYPE string, 64 | final_type TYPE string, 65 | type_definition TYPE string, 66 | id TYPE i, 67 | END OF t_hierarchy, 68 | tt_hierarchy TYPE STANDARD TABLE OF t_hierarchy WITH DEFAULT KEY. 69 | CONSTANTS: c_components TYPE string VALUE '&&components&&'. 70 | DATA: hierarchy TYPE tt_hierarchy. 71 | 72 | METHODS: build_structure IMPORTING i_data TYPE REF TO data 73 | EXPORTING e_data TYPE string. 74 | PRIVATE SECTION. 75 | DATA: current_id TYPE i. 76 | METHODS check_component 77 | IMPORTING 78 | i_comp TYPE abap_compdescr 79 | VALUE(i_data) TYPE REF TO data 80 | VALUE(i_parent) TYPE abap_abstypename 81 | i_level TYPE i 82 | i_keep_level TYPE abap_bool DEFAULT abap_false 83 | i_keep_id TYPE abap_bool DEFAULT abap_false. 84 | METHODS check_object 85 | IMPORTING 86 | VALUE(i_data) TYPE REF TO data 87 | VALUE(i_parent) TYPE abap_abstypename 88 | i_abap_type TYPE REF TO cl_abap_structdescr 89 | i_level TYPE i. 90 | METHODS create_types RETURNING VALUE(r_definition) TYPE string. 91 | METHODS: get_id RETURNING VALUE(r_id) TYPE i. 92 | METHODS: display. 93 | METHODS: get_types RETURNING VALUE(r_types) TYPE string, 94 | init, 95 | get_internal_types 96 | CHANGING 97 | VALUE(c_type) TYPE t_hierarchy. 98 | ENDCLASS. 99 | 100 | 101 | START-OF-SELECTION. 102 | DATA(hlp) = NEW lcl_hlp( ). 103 | 104 | CALL SCREEN 0100. 105 | 106 | 107 | 108 | 109 | *&---------------------------------------------------------------------* 110 | *& Module PBO OUTPUT 111 | *&---------------------------------------------------------------------* 112 | * text 113 | *----------------------------------------------------------------------* 114 | MODULE pbo OUTPUT. 115 | SET PF-STATUS 'STATUS_0100'. 116 | SET TITLEBAR 'TITLE'. 117 | hlp->create_source_editor( ). 118 | ENDMODULE. 119 | *&---------------------------------------------------------------------* 120 | *& Module PAI INPUT 121 | *&---------------------------------------------------------------------* 122 | * text 123 | *----------------------------------------------------------------------* 124 | MODULE pai INPUT. 125 | hlp->pai( ok_code ). 126 | ENDMODULE. 127 | 128 | CLASS lcl_hlp IMPLEMENTATION. 129 | 130 | METHOD constructor. 131 | converter = NEW #( ). 132 | ENDMETHOD. 133 | 134 | METHOD create_source_editor. 135 | 136 | IF source_editor IS INITIAL. 137 | source_editor = NEW #( parent = NEW cl_gui_docking_container( side = cl_gui_docking_container=>dock_at_left 138 | no_autodef_progid_dynnr = abap_true 139 | extension = 500 ) ) . 140 | ENDIF. 141 | 142 | ENDMETHOD. 143 | 144 | METHOD convert. 145 | DATA: source TYPE soli_tab. 146 | source_editor->get_text_as_stream( 147 | IMPORTING 148 | text = source 149 | EXCEPTIONS 150 | error_cntl_call_method = 1 151 | OTHERS = 3 152 | ). 153 | IF sy-subrc EQ 0. 154 | 155 | IF source IS INITIAL. 156 | MESSAGE s001(00) WITH 'Data input is required' DISPLAY LIKE 'E' ##MG_MISSING ##NO_TEXT. 157 | RETURN. 158 | ENDIF. 159 | 160 | * DATA(json_data) = /ui2/cl_json=>generate( 161 | DATA(json_data) = zui2_json=>generate( 162 | json = cl_bcs_convert=>txt_to_string( it_soli = source ) 163 | pretty_name = get_pretty_name_mode( ) 164 | ). 165 | 166 | IF json_data IS INITIAL. 167 | MESSAGE s001(00) WITH 'Problem converting JSON.' DISPLAY LIKE 'E' ##MG_MISSING ##NO_TEXT. 168 | ELSE. 169 | 170 | converter->build_structure( 171 | EXPORTING 172 | i_data = json_data 173 | IMPORTING 174 | e_data = results 175 | ). 176 | 177 | DATA: target TYPE STANDARD TABLE OF t_source. 178 | SPLIT results AT cl_abap_char_utilities=>newline INTO TABLE target. 179 | pretty_print_code( CHANGING c_source = target ). 180 | 181 | call_editor( CHANGING c_source = target ). 182 | 183 | ENDIF. 184 | ENDIF. 185 | ENDMETHOD. 186 | 187 | METHOD call_editor. 188 | 189 | IF abap_editor IS INITIAL. 190 | DATA(container) = NEW cl_gui_custom_container( container_name = 'CC_INPUT' ). 191 | abap_editor = NEW #( parent = container ). 192 | ENDIF. 193 | 194 | abap_editor->draw( ). 195 | abap_editor->set_text( c_source ). 196 | abap_editor->undraw( ). 197 | 198 | ENDMETHOD. 199 | 200 | 201 | 202 | METHOD pretty_print_code. 203 | 204 | CALL FUNCTION 'PRETTY_PRINTER' 205 | EXPORTING 206 | inctoo = abap_false " X = Process Include Programs as Well 207 | TABLES 208 | ntext = c_source " Table of Formatted Source Code 209 | otext = c_source " Table of Source Code Pending Editing 210 | EXCEPTIONS 211 | enqueue_table_full = 0 212 | include_enqueued = 0 213 | include_readerror = 0 214 | include_writeerror = 0 215 | OTHERS = 0. 216 | ENDMETHOD. 217 | 218 | 219 | 220 | METHOD pai. 221 | CLEAR sy-ucomm. 222 | CASE i_okcode. 223 | WHEN 'BACK' OR 'UP' OR 'EXIT'. 224 | LEAVE PROGRAM. 225 | WHEN 'CONVERT'. 226 | convert( ). 227 | ENDCASE. 228 | ENDMETHOD. 229 | 230 | METHOD get_pretty_name_mode. 231 | 232 | pretty_name_mode = COND #( WHEN p_none EQ abap_true THEN zui2_json=>pretty_mode-none 233 | WHEN p_camel EQ abap_true THEN zui2_json=>pretty_mode-camel_case 234 | WHEN p_ext EQ abap_true THEN zui2_json=>pretty_mode-extended 235 | WHEN p_low EQ abap_true THEN zui2_json=>pretty_mode-low_case 236 | WHEN p_user EQ abap_true THEN zui2_json=>pretty_mode-user 237 | WHEN p_userlo EQ abap_true THEN zui2_json=>pretty_mode-user_low_case 238 | WHEN P_cases EQ abap_true THEN zui2_json=>pretty_mode-case_sensitive 239 | ELSE zui2_json=>pretty_mode-extended 240 | ). 241 | ENDMETHOD. 242 | 243 | ENDCLASS. 244 | 245 | 246 | CLASS lcl_json_structure IMPLEMENTATION. 247 | METHOD get_id. 248 | ADD 1 TO current_id. 249 | r_id = current_id. 250 | ENDMETHOD. 251 | METHOD build_structure. 252 | init( ). 253 | DATA: level TYPE i VALUE 0, 254 | abap_type TYPE REF TO cl_abap_structdescr, 255 | abap_ref_type TYPE REF TO cl_abap_refdescr. 256 | FIELD-SYMBOLS:
TYPE ANY TABLE. 257 | 258 | TRY. 259 | DATA(abap_type_table) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data_ref( p_data_ref = i_data ) ). 260 | ASSIGN i_data->* TO
. 261 | LOOP AT
ASSIGNING FIELD-SYMBOL(). 262 | EXIT. 263 | ENDLOOP. 264 | 265 | APPEND VALUE #( level = level name = 'JSON' type = abap_type_table->type_kind absolute_type = abap_type_table->absolute_name table = abap_true id = get_id( ) ) TO hierarchy. 266 | abap_type = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data_ref( p_data_ref = ) ). 267 | 268 | ADD 1 TO level. 269 | APPEND VALUE #( level = level name = 'JSON' type = abap_type->type_kind absolute_type = abap_type->absolute_name structure = abap_true id = get_id( ) ) TO hierarchy. 270 | check_object( i_abap_type = abap_type 271 | i_level = level 272 | i_data = 273 | i_parent = '' ). 274 | 275 | CATCH cx_sy_move_cast_error. 276 | abap_type = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data_ref( p_data_ref = i_data ) ). 277 | APPEND VALUE #( level = level name = 'JSON' type = abap_type->type_kind absolute_type = abap_type->absolute_name structure = abap_true id = get_id( ) ) TO hierarchy. 278 | check_object( i_abap_type = abap_type i_level = level i_data = i_data i_parent = '' ). 279 | ENDTRY. 280 | e_data = create_types( ). 281 | ENDMETHOD. 282 | 283 | METHOD init. 284 | 285 | REFRESH: hierarchy. 286 | CLEAR current_id. 287 | 288 | ENDMETHOD. 289 | 290 | METHOD display. 291 | cl_demo_output=>display( create_types( ) ). 292 | ENDMETHOD. 293 | METHOD check_object. 294 | 295 | LOOP AT i_abap_type->components ASSIGNING FIELD-SYMBOL(). 296 | DATA(field) = |i_data->{ -name }|. 297 | ASSIGN (field) TO FIELD-SYMBOL(). 298 | IF IS ASSIGNED AND IS NOT INITIAL. 299 | 300 | check_component( 301 | i_parent = i_abap_type->absolute_name 302 | i_comp = 303 | i_data = 304 | i_level = i_level ). 305 | 306 | ENDIF. 307 | UNASSIGN . 308 | ENDLOOP. 309 | 310 | ENDMETHOD. "#EC CI_VALPAR 311 | 312 | METHOD check_component. 313 | 314 | DATA level TYPE i VALUE 0. 315 | IF i_keep_level EQ abap_false. 316 | level = i_level + 1. 317 | ELSE. 318 | level = i_level. 319 | ENDIF. 320 | TRY. 321 | DATA(str_type) = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_data_ref( p_data_ref = i_data ) ). 322 | 323 | check_object( i_parent = i_parent 324 | i_data = i_data 325 | i_abap_type = str_type 326 | i_level = level 327 | ). 328 | APPEND VALUE #( level = level name = i_comp-name type = str_type->type_kind absolute_type = str_type->absolute_name parent = i_parent structure = abap_true id = get_id( ) ) TO hierarchy. 329 | CATCH cx_root. 330 | 331 | TRY. 332 | DATA(table_type) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data_ref( p_data_ref = i_data ) ). 333 | IF i_keep_id EQ abap_false. 334 | DATA(id) = get_id( ). 335 | APPEND VALUE #( level = level name = i_comp-name type = table_type->type_kind absolute_type = table_type->absolute_name parent = i_parent table = abap_true id = id ) TO hierarchy. 336 | ELSE. 337 | id = current_id. 338 | ENDIF. 339 | 340 | FIELD-SYMBOLS: TYPE STANDARD TABLE, 341 | TYPE any. 342 | ASSIGN i_data->* TO . 343 | TRY. 344 | ASSIGN [ 1 ] TO . 345 | IF sy-subrc NE 0. 346 | APPEND INITIAL LINE TO ASSIGNING . 347 | ENDIF. 348 | CATCH cx_root. 349 | APPEND INITIAL LINE TO ASSIGNING . 350 | ENDTRY. 351 | 352 | cl_abap_structdescr=>describe_by_data_ref( EXPORTING p_data_ref = 353 | RECEIVING p_descr_ref = DATA(table_line_ref) 354 | EXCEPTIONS OTHERS = 1 ). 355 | IF sy-subrc NE 0. 356 | DATA: table_of_strings TYPE STANDARD TABLE OF string. 357 | check_component( 358 | EXPORTING 359 | i_comp = i_comp 360 | i_data = REF #( table_of_strings ) 361 | i_parent = i_parent 362 | i_level = i_level 363 | i_keep_level = abap_true 364 | i_keep_id = abap_true 365 | ). 366 | RETURN. 367 | ENDIF. 368 | 369 | DATA(table_line_type) = CAST cl_abap_structdescr( table_line_ref ). 370 | APPEND VALUE #( level = level name = i_comp-name type = table_line_type->type_kind absolute_type = table_line_type->absolute_name parent = table_type->absolute_name structure = abap_true id = id ) TO hierarchy. 371 | 372 | check_object( i_parent = table_type->absolute_name 373 | i_data = 374 | i_abap_type = table_line_type 375 | i_level = level 376 | ). 377 | 378 | CATCH cx_root. 379 | "May be a table of strings or integers. 380 | IF table_type IS NOT INITIAL. 381 | TRY. 382 | IF table_type->type_kind EQ 'h'. 383 | DATA(table_line_as_el_type) = CAST cl_abap_elemdescr( cl_abap_elemdescr=>describe_by_data_ref( p_data_ref = ) ). 384 | ADD 1 TO level. 385 | APPEND VALUE #( level = level name = i_comp-name type = table_line_as_el_type->type_kind absolute_type = table_line_as_el_type->absolute_name parent = table_line_as_el_type->absolute_name structure = abap_true id = id ) TO hierarchy. 386 | ENDIF. 387 | CATCH cx_root. 388 | TRY. 389 | IF table_type->type_kind EQ 'h'. 390 | table_line_as_el_type = CAST cl_abap_elemdescr( cl_abap_elemdescr=>describe_by_data( p_data = ) ). 391 | ADD 1 TO level. 392 | APPEND VALUE #( level = level name = i_comp-name type = table_line_as_el_type->type_kind absolute_type = table_line_as_el_type->absolute_name parent = table_line_as_el_type->absolute_name structure = abap_true id = id ) TO hierarchy. 393 | ENDIF. 394 | CATCH cx_root. 395 | 396 | DATA(other_type) = cl_abap_typedescr=>describe_by_data_ref( p_data_ref = i_data ) . 397 | APPEND VALUE #( level = level name = i_comp-name type = other_type->type_kind length = other_type->length decimals = other_type->decimals absolute_type = other_type->absolute_name parent = i_parent ) TO hierarchy. 398 | ENDTRY. 399 | 400 | ENDTRY. 401 | ELSE. 402 | other_type = cl_abap_typedescr=>describe_by_data_ref( p_data_ref = i_data ) . 403 | APPEND VALUE #( level = level name = i_comp-name type = other_type->type_kind length = other_type->length decimals = other_type->decimals absolute_type = other_type->absolute_name parent = i_parent ) TO hierarchy. 404 | ENDIF. 405 | ENDTRY. 406 | ENDTRY. 407 | ENDMETHOD. "#EC CI_VALPAR 408 | 409 | METHOD create_types. 410 | DATA: components TYPE string. 411 | LOOP AT hierarchy ASSIGNING FIELD-SYMBOL(). 412 | IF -structure EQ abap_true AND -type NE 'g'. 413 | -final_type = |{ -name } type t_{ -name }{ -id }| ##NO_TEXT. 414 | -type_definition = |types: begin of t_{ -name }{ -id },{ cl_abap_char_utilities=>newline }{ c_components }end of t_{ -name }{ -id }.| ##NO_TEXT. 415 | ELSEIF -structure EQ abap_true. 416 | -final_type = |{ -name } type t_{ -name }{ -id }| ##NO_TEXT. 417 | get_internal_types( CHANGING c_type = ). 418 | -type_definition = |types: t_{ -name }{ -id } type { -absolute_type }.| ##NO_TEXT. 419 | ELSEIF -table EQ abap_true. 420 | -final_type = |{ -name } type tt_{ -name }{ -id }| ##NO_TEXT. 421 | -type_definition = |types: tt_{ -name }{ -id } type standard table of t_{ -name }{ -id } with default key.| ##NO_TEXT. 422 | ELSE. 423 | 424 | get_internal_types( CHANGING c_type = ). 425 | ENDIF. 426 | ENDLOOP. 427 | 428 | LOOP AT hierarchy ASSIGNING GROUP BY ( parent = -parent ). 429 | CLEAR components. 430 | LOOP AT GROUP ASSIGNING FIELD-SYMBOL(). 431 | components = components && -final_type && ',' && cl_abap_char_utilities=>newline. 432 | ENDLOOP. 433 | ASSIGN hierarchy[ absolute_type = -parent ] TO FIELD-SYMBOL(). 434 | IF sy-subrc EQ 0. 435 | REPLACE ALL OCCURRENCES OF c_components IN -type_definition WITH components. 436 | ENDIF. 437 | ENDLOOP. 438 | 439 | SORT hierarchy BY level DESCENDING structure DESCENDING. 440 | LOOP AT hierarchy ASSIGNING WHERE structure EQ abap_true 441 | OR table EQ abap_true. 442 | r_definition = r_definition && -type_definition && cl_abap_char_utilities=>newline. 443 | ENDLOOP. 444 | ENDMETHOD. 445 | 446 | METHOD get_types. 447 | r_types = create_types( ). 448 | ENDMETHOD. 449 | 450 | METHOD get_internal_types. 451 | REPLACE FIRST OCCURRENCE OF REGEX '\\TYPE-POOL=(.*)\\TYPE=' IN c_type-absolute_type WITH ''. 452 | IF sy-subrc EQ 0. 453 | c_type-final_type = |{ c_type-name } type { c_type-absolute_type }|. 454 | RETURN. 455 | ELSE. 456 | REPLACE FIRST OCCURRENCE OF '\TYPE=' IN c_type-absolute_type WITH ' '. 457 | ENDIF. 458 | 459 | IF c_type-type EQ cl_abap_typedescr=>typekind_char. 460 | c_type-final_type = |{ c_type-name } type { c_type-absolute_type } length { c_type-length }|. 461 | ELSEIF c_type-type EQ cl_abap_typedescr=>typekind_packed. 462 | c_type-final_type = |{ c_type-name } type { c_type-type } length { c_type-length } decimals { c_type-decimals }|. 463 | ELSEIF c_type-type EQ cl_abap_typedescr=>typekind_num. 464 | c_type-final_type = |{ c_type-name } type { c_type-absolute_type } length { c_type-length }|. 465 | ELSE. 466 | c_type-final_type = |{ c_type-name } type { c_type-absolute_type }|. 467 | ENDIF. 468 | ENDMETHOD. "#EC CI_VALPAR 469 | ENDCLASS. 470 | -------------------------------------------------------------------------------- /src/zui2_json.clas.abap: -------------------------------------------------------------------------------- 1 | *----------------------------------------------------------------------* 2 | * CLASS ZUI2_JSON DEFINITION 3 | *----------------------------------------------------------------------* 4 | * 5 | *----------------------------------------------------------------------* 6 | CLASS zui2_json DEFINITION 7 | PUBLIC 8 | CREATE PUBLIC . 9 | 10 | PUBLIC SECTION. 11 | TYPE-POOLS abap . 12 | CLASS cl_abap_tstmp DEFINITION LOAD . 13 | CLASS cx_sy_conversion_error DEFINITION LOAD . 14 | 15 | TYPES json TYPE string . 16 | TYPES: 17 | BEGIN OF name_mapping, 18 | abap TYPE abap_compname, 19 | json TYPE string, 20 | END OF name_mapping . 21 | TYPES: 22 | name_mappings TYPE HASHED TABLE OF name_mapping WITH UNIQUE KEY abap . 23 | TYPES bool TYPE char1 . 24 | TYPES tribool TYPE char1 . 25 | TYPES pretty_name_mode TYPE char1 . 26 | 27 | CONSTANTS: 28 | BEGIN OF pretty_mode, 29 | none TYPE char1 VALUE ``, 30 | low_case TYPE char1 VALUE `L`, 31 | camel_case TYPE char1 VALUE `X`, 32 | extended TYPE char1 VALUE `Y`, 33 | user TYPE char1 VALUE `U`, 34 | user_low_case TYPE char1 VALUE `C`, 35 | case_sensitive TYPE char1 VALUE 'S', 36 | END OF pretty_mode . 37 | CONSTANTS: 38 | BEGIN OF c_bool, 39 | true TYPE bool VALUE `X`, 40 | false TYPE bool VALUE ``, 41 | END OF c_bool . 42 | CONSTANTS: 43 | BEGIN OF c_tribool, 44 | true TYPE tribool VALUE c_bool-true, 45 | false TYPE tribool VALUE `-`, 46 | undefined TYPE tribool VALUE ``, 47 | END OF c_tribool . 48 | CLASS-DATA sv_white_space TYPE string READ-ONLY . 49 | CONSTANTS mc_key_separator TYPE string VALUE `-` ##NO_TEXT. 50 | CLASS-DATA mc_bool_types TYPE string READ-ONLY VALUE `\TYPE-POOL=ABAP\TYPE=ABAP_BOOL\TYPE=BOOLEAN\TYPE=BOOLE_D\TYPE=XFELD` ##NO_TEXT. 51 | CLASS-DATA mc_bool_3state TYPE string READ-ONLY VALUE `\TYPE=BOOLEAN` ##NO_TEXT. 52 | CONSTANTS version TYPE i VALUE 6 ##NO_TEXT. 53 | CLASS-DATA mc_json_type TYPE string READ-ONLY . 54 | 55 | CLASS-METHODS class_constructor . 56 | CLASS-METHODS string_to_xstring 57 | IMPORTING 58 | !in TYPE string 59 | CHANGING 60 | VALUE(out) TYPE any . 61 | CLASS-METHODS xstring_to_string 62 | IMPORTING 63 | !in TYPE any 64 | RETURNING 65 | VALUE(out) TYPE string . 66 | CLASS-METHODS raw_to_string 67 | IMPORTING 68 | !iv_xstring TYPE xstring 69 | !iv_encoding TYPE abap_encoding OPTIONAL 70 | RETURNING 71 | VALUE(rv_string) TYPE string . 72 | CLASS-METHODS string_to_raw 73 | IMPORTING 74 | !iv_string TYPE string 75 | !iv_encoding TYPE abap_encoding OPTIONAL 76 | RETURNING 77 | VALUE(rv_xstring) TYPE xstring . 78 | CLASS-METHODS dump 79 | IMPORTING 80 | !data TYPE data 81 | !compress TYPE bool DEFAULT c_bool-false 82 | !type_descr TYPE REF TO cl_abap_typedescr OPTIONAL 83 | !pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none 84 | !assoc_arrays TYPE bool DEFAULT c_bool-false 85 | !ts_as_iso8601 TYPE bool DEFAULT c_bool-false 86 | RETURNING 87 | VALUE(r_json) TYPE json . 88 | CLASS-METHODS deserialize 89 | IMPORTING 90 | !json TYPE json OPTIONAL 91 | !jsonx TYPE xstring OPTIONAL 92 | !pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none 93 | !assoc_arrays TYPE bool DEFAULT c_bool-false 94 | !assoc_arrays_opt TYPE bool DEFAULT c_bool-false 95 | !name_mappings TYPE name_mappings OPTIONAL 96 | CHANGING 97 | !data TYPE data . 98 | CLASS-METHODS serialize 99 | IMPORTING 100 | !data TYPE data 101 | !compress TYPE bool DEFAULT c_bool-false 102 | !name TYPE string OPTIONAL 103 | !pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none 104 | !type_descr TYPE REF TO cl_abap_typedescr OPTIONAL 105 | !assoc_arrays TYPE bool DEFAULT c_bool-false 106 | !ts_as_iso8601 TYPE bool DEFAULT c_bool-false 107 | !expand_includes TYPE bool DEFAULT c_bool-true 108 | !assoc_arrays_opt TYPE bool DEFAULT c_bool-false 109 | !numc_as_string TYPE bool DEFAULT c_bool-false 110 | !name_mappings TYPE name_mappings OPTIONAL 111 | RETURNING 112 | VALUE(r_json) TYPE json . 113 | METHODS deserialize_int 114 | IMPORTING 115 | !json TYPE json OPTIONAL 116 | !jsonx TYPE xstring OPTIONAL 117 | CHANGING 118 | !data TYPE data 119 | RAISING 120 | cx_sy_move_cast_error . 121 | CLASS-METHODS generate 122 | IMPORTING 123 | !json TYPE json 124 | !pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none 125 | !name_mappings TYPE name_mappings OPTIONAL 126 | RETURNING 127 | VALUE(rr_data) TYPE REF TO data . 128 | METHODS serialize_int 129 | IMPORTING 130 | !data TYPE data 131 | !name TYPE string OPTIONAL 132 | !type_descr TYPE REF TO cl_abap_typedescr OPTIONAL 133 | RETURNING 134 | VALUE(r_json) TYPE json . 135 | METHODS generate_int 136 | IMPORTING 137 | !json TYPE json 138 | RETURNING 139 | VALUE(rr_data) TYPE REF TO data . 140 | METHODS constructor 141 | IMPORTING 142 | !compress TYPE bool DEFAULT c_bool-false 143 | !pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none 144 | !assoc_arrays TYPE bool DEFAULT c_bool-false 145 | !ts_as_iso8601 TYPE bool DEFAULT c_bool-false 146 | !expand_includes TYPE bool DEFAULT c_bool-true 147 | !assoc_arrays_opt TYPE bool DEFAULT c_bool-false 148 | !strict_mode TYPE bool DEFAULT c_bool-false 149 | !numc_as_string TYPE bool DEFAULT c_bool-false 150 | !name_mappings TYPE name_mappings OPTIONAL . 151 | CLASS-METHODS bool_to_tribool 152 | IMPORTING 153 | !iv_bool TYPE bool 154 | RETURNING 155 | VALUE(rv_tribool) TYPE tribool . 156 | CLASS-METHODS tribool_to_bool 157 | IMPORTING 158 | !iv_tribool TYPE tribool 159 | RETURNING 160 | VALUE(rv_bool) TYPE bool . 161 | protected section. 162 | 163 | types: 164 | BEGIN OF t_s_symbol, 165 | header TYPE string, 166 | name TYPE string, 167 | type TYPE REF TO cl_abap_datadescr, 168 | value TYPE REF TO data, 169 | compressable TYPE abap_bool, 170 | read_only TYPE abap_bool, 171 | END OF t_s_symbol . 172 | types: 173 | t_t_symbol TYPE STANDARD TABLE OF t_s_symbol WITH DEFAULT KEY . 174 | types: 175 | BEGIN OF t_s_field_cache, 176 | name TYPE string, 177 | type TYPE REF TO cl_abap_datadescr, 178 | value TYPE REF TO data, 179 | END OF t_s_field_cache . 180 | types: 181 | t_t_field_cache TYPE HASHED TABLE OF t_s_field_cache WITH UNIQUE KEY name . 182 | types: 183 | name_mappings_ex TYPE HASHED TABLE OF name_mapping WITH UNIQUE KEY json . 184 | 185 | data MV_COMPRESS type BOOL . 186 | data MV_PRETTY_NAME type PRETTY_NAME_MODE . 187 | data MV_ASSOC_ARRAYS type BOOL . 188 | data MV_TS_AS_ISO8601 type BOOL . 189 | data MT_NAME_MAPPINGS type NAME_MAPPINGS . 190 | data MT_NAME_MAPPINGS_EX type NAME_MAPPINGS_EX . 191 | data MV_EXPAND_INCLUDES type BOOL . 192 | data MV_ASSOC_ARRAYS_OPT type BOOL . 193 | data MV_STRICT_MODE type BOOL . 194 | data MV_NUMC_AS_STRING type BOOL . 195 | 196 | methods GET_SYMBOLS 197 | final 198 | importing 199 | !TYPE_DESCR type ref to CL_ABAP_TYPEDESCR 200 | !DATA type ref to DATA optional 201 | !OBJECT type ref to OBJECT optional 202 | !INCLUDE_ALIASES type ABAP_BOOL default ABAP_FALSE 203 | returning 204 | value(RESULT) type T_T_SYMBOL . 205 | methods DUMP_SYMBOLS 206 | final 207 | importing 208 | !IT_SYMBOLS type T_T_SYMBOL 209 | returning 210 | value(R_JSON) type JSON . 211 | methods GET_FIELDS 212 | final 213 | importing 214 | !TYPE_DESCR type ref to CL_ABAP_TYPEDESCR 215 | !DATA type ref to DATA optional 216 | !OBJECT type ref to OBJECT optional 217 | returning 218 | value(RT_FIELDS) type T_T_FIELD_CACHE . 219 | methods DUMP_INT 220 | importing 221 | !DATA type DATA 222 | !TYPE_DESCR type ref to CL_ABAP_TYPEDESCR optional 223 | returning 224 | value(R_JSON) type JSON . 225 | methods IS_COMPRESSABLE 226 | importing 227 | !TYPE_DESCR type ref to CL_ABAP_TYPEDESCR 228 | !NAME type CSEQUENCE 229 | returning 230 | value(RV_COMPRESS) type ABAP_BOOL . 231 | methods RESTORE 232 | importing 233 | !JSON type JSON 234 | !LENGTH type I 235 | value(TYPE_DESCR) type ref to CL_ABAP_TYPEDESCR optional 236 | !FIELD_CACHE type T_T_FIELD_CACHE optional 237 | changing 238 | !DATA type DATA optional 239 | !OFFSET type I default 0 240 | raising 241 | CX_SY_MOVE_CAST_ERROR . 242 | methods RESTORE_TYPE 243 | importing 244 | !JSON type JSON 245 | !LENGTH type I 246 | value(TYPE_DESCR) type ref to CL_ABAP_TYPEDESCR optional 247 | !FIELD_CACHE type T_T_FIELD_CACHE optional 248 | changing 249 | !DATA type DATA optional 250 | !OFFSET type I default 0 251 | raising 252 | CX_SY_MOVE_CAST_ERROR . 253 | methods DUMP_TYPE 254 | importing 255 | !DATA type DATA 256 | !TYPE_DESCR type ref to CL_ABAP_ELEMDESCR 257 | returning 258 | value(R_JSON) type JSON . 259 | methods DUMP_TYPE_EX 260 | importing 261 | !DATA type DATA 262 | returning 263 | value(R_JSON) type JSON . 264 | methods PRETTY_NAME_EX 265 | importing 266 | !IN type CSEQUENCE 267 | returning 268 | value(OUT) type STRING . 269 | methods GENERATE_INT_EX 270 | final 271 | importing 272 | !JSON type JSON 273 | !LENGTH type I 274 | changing 275 | !DATA type DATA 276 | !OFFSET type I . 277 | methods PRETTY_NAME 278 | importing 279 | !IN type CSEQUENCE 280 | returning 281 | value(OUT) type STRING . 282 | class-methods ESCAPE 283 | importing 284 | !IN type ANY 285 | returning 286 | value(OUT) type STRING . 287 | class-methods EDM_DATETIME_TO_TS 288 | importing 289 | !TICKS type STRING 290 | !OFFSET type STRING optional 291 | !TYPEKIND type ABAP_TYPEKIND 292 | returning 293 | value(R_DATA) type STRING . 294 | private section. 295 | 296 | data MV_EXTENDED type BOOL . 297 | class-data MC_ME_TYPE type STRING . 298 | *"* private components of class ZUI2_JSON 299 | *"* do not include other source files here!!! 300 | ENDCLASS. 301 | 302 | 303 | 304 | CLASS ZUI2_JSON IMPLEMENTATION. 305 | 306 | 307 | METHOD BOOL_TO_TRIBOOL. 308 | IF iv_bool EQ c_bool-true. 309 | rv_tribool = c_tribool-true. 310 | ELSEIF iv_bool EQ abap_undefined. " fall back for abap _bool 311 | rv_tribool = c_tribool-undefined. 312 | ELSE. 313 | rv_tribool = c_tribool-false. 314 | ENDIF. 315 | ENDMETHOD. "bool_to_tribool 316 | 317 | 318 | METHOD CLASS_CONSTRUCTOR. 319 | 320 | DATA: lo_bool_type_descr TYPE REF TO cl_abap_typedescr, 321 | lo_tribool_type_descr TYPE REF TO cl_abap_typedescr, 322 | lo_json_type_descr TYPE REF TO cl_abap_typedescr, 323 | lv_pos LIKE sy-fdpos, 324 | lv_json_string TYPE json. 325 | 326 | lo_bool_type_descr = cl_abap_typedescr=>describe_by_data( c_bool-true ). 327 | lo_tribool_type_descr = cl_abap_typedescr=>describe_by_data( c_tribool-true ). 328 | lo_json_type_descr = cl_abap_typedescr=>describe_by_data( lv_json_string ). 329 | 330 | CONCATENATE mc_bool_types lo_bool_type_descr->absolute_name lo_tribool_type_descr->absolute_name INTO mc_bool_types. 331 | CONCATENATE mc_bool_3state lo_tribool_type_descr->absolute_name INTO mc_bool_3state. 332 | CONCATENATE mc_json_type lo_json_type_descr->absolute_name INTO mc_json_type. 333 | 334 | FIND FIRST OCCURRENCE OF `\TYPE=` IN lo_json_type_descr->absolute_name MATCH OFFSET lv_pos. 335 | IF sy-subrc IS INITIAL. 336 | mc_me_type = lo_json_type_descr->absolute_name(lv_pos). 337 | ENDIF. 338 | 339 | sv_white_space = cl_abap_char_utilities=>get_simple_spaces_for_cur_cp( ). 340 | 341 | ENDMETHOD. "class_constructor 342 | 343 | 344 | METHOD CONSTRUCTOR. 345 | 346 | DATA: rtti TYPE REF TO cl_abap_classdescr, 347 | pair LIKE LINE OF name_mappings. 348 | 349 | mv_compress = compress. 350 | mv_pretty_name = pretty_name. 351 | mv_assoc_arrays = assoc_arrays. 352 | mv_ts_as_iso8601 = ts_as_iso8601. 353 | mv_expand_includes = expand_includes. 354 | mv_assoc_arrays_opt = assoc_arrays_opt. 355 | mv_strict_mode = strict_mode. 356 | mv_numc_as_string = numc_as_string. 357 | 358 | LOOP AT name_mappings INTO pair. 359 | TRANSLATE pair-abap TO UPPER CASE. 360 | INSERT pair INTO TABLE mt_name_mappings. 361 | ENDLOOP. 362 | 363 | INSERT LINES OF mt_name_mappings INTO TABLE mt_name_mappings_ex. 364 | 365 | IF mt_name_mappings IS NOT INITIAL. 366 | IF mv_pretty_name EQ pretty_mode-none. 367 | mv_pretty_name = pretty_mode-user. 368 | ELSEIF pretty_name EQ pretty_mode-low_case. 369 | mv_pretty_name = pretty_mode-user_low_case. 370 | ENDIF. 371 | ENDIF. 372 | 373 | rtti ?= cl_abap_classdescr=>describe_by_object_ref( me ). 374 | IF rtti->absolute_name NE mc_me_type. 375 | mv_extended = c_bool-true. 376 | ENDIF. 377 | 378 | ENDMETHOD. 379 | 380 | 381 | METHOD DESERIALIZE. 382 | 383 | DATA: lo_json TYPE REF TO ZUI2_JSON. 384 | 385 | " ********************************************************************** 386 | "! Usage examples and documentation can be found on SCN: 387 | " http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer 388 | " ********************************************************************** " 389 | 390 | IF json IS NOT INITIAL OR jsonx IS NOT INITIAL. 391 | 392 | CREATE OBJECT lo_json 393 | EXPORTING 394 | pretty_name = pretty_name 395 | name_mappings = name_mappings 396 | assoc_arrays = assoc_arrays 397 | assoc_arrays_opt = assoc_arrays_opt. 398 | 399 | TRY . 400 | lo_json->deserialize_int( EXPORTING json = json jsonx = jsonx CHANGING data = data ). 401 | CATCH cx_sy_move_cast_error. 402 | ENDTRY. 403 | 404 | ENDIF. 405 | 406 | ENDMETHOD. "deserialize 407 | 408 | 409 | METHOD DESERIALIZE_INT. 410 | 411 | DATA: length TYPE i, 412 | unescaped LIKE json. 413 | 414 | " ********************************************************************** 415 | "! Usage examples and documentation can be found on SCN: 416 | " http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer 417 | " ********************************************************************** " 418 | 419 | IF json IS NOT INITIAL OR jsonx IS NOT INITIAL. 420 | 421 | IF jsonx IS NOT INITIAL. 422 | unescaped = raw_to_string( jsonx ). 423 | ELSE. 424 | unescaped = json. 425 | ENDIF. 426 | 427 | " to eliminate numeric replacement calls for every single sting value, we do 428 | " replacement over all JSON text, while this shall not destroy JSON structure 429 | REPLACE ALL OCCURRENCES OF `\r\n` IN unescaped WITH cl_abap_char_utilities=>cr_lf. 430 | REPLACE ALL OCCURRENCES OF `\n` IN unescaped WITH cl_abap_char_utilities=>newline. 431 | REPLACE ALL OCCURRENCES OF `\t` IN unescaped WITH cl_abap_char_utilities=>horizontal_tab. 432 | " REPLACE ALL OCCURRENCES OF `\f` IN r_json WITH cl_abap_char_utilities=>form_feed. 433 | " REPLACE ALL OCCURRENCES OF `\b` IN r_json WITH cl_abap_char_utilities=>backspace. 434 | 435 | length = NUMOFCHAR( unescaped ). 436 | restore_type( EXPORTING json = unescaped length = length CHANGING data = data ). 437 | 438 | ENDIF. 439 | 440 | ENDMETHOD. "deserialize 441 | 442 | 443 | METHOD DUMP. 444 | 445 | DATA: lo_json TYPE REF TO ZUI2_JSON. 446 | 447 | CREATE OBJECT lo_json 448 | EXPORTING 449 | compress = compress 450 | pretty_name = pretty_name 451 | assoc_arrays = assoc_arrays 452 | ts_as_iso8601 = ts_as_iso8601. 453 | 454 | r_json = lo_json->dump_int( data = data type_descr = type_descr ). 455 | 456 | ENDMETHOD. "dump 457 | 458 | 459 | METHOD DUMP_INT. 460 | 461 | DATA: lo_typedesc TYPE REF TO cl_abap_typedescr, 462 | lo_elem_descr TYPE REF TO cl_abap_elemdescr, 463 | lo_classdesc TYPE REF TO cl_abap_classdescr, 464 | lo_structdesc TYPE REF TO cl_abap_structdescr, 465 | lo_tabledescr TYPE REF TO cl_abap_tabledescr, 466 | lt_symbols TYPE t_t_symbol, 467 | lt_keys LIKE lt_symbols, 468 | lt_properties TYPE STANDARD TABLE OF string, 469 | lt_fields TYPE STANDARD TABLE OF string, 470 | lo_obj_ref TYPE REF TO object, 471 | lo_data_ref TYPE REF TO data, 472 | ls_skip_key TYPE LINE OF abap_keydescr_tab, 473 | lv_array_opt TYPE abap_bool, 474 | lv_prop_name TYPE string, 475 | lv_keyval TYPE string, 476 | lv_itemval TYPE string. 477 | 478 | FIELD-SYMBOLS: TYPE ANY, 479 | TYPE ANY, 480 | TYPE data, 481 | TYPE LINE OF abap_keydescr_tab, 482 | LIKE LINE OF lt_symbols, 483 |
TYPE ANY TABLE. 484 | 485 | " we need here macro instead of method calls because of the performance reasons. 486 | " based on SAT measurements. 487 | 488 | CASE type_descr->kind. 489 | WHEN cl_abap_typedescr=>kind_ref. 490 | 491 | IF data IS INITIAL. 492 | r_json = `null`. "#EC NOTEXT 493 | ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. 494 | lo_data_ref ?= data. 495 | lo_typedesc = cl_abap_typedescr=>describe_by_data_ref( lo_data_ref ). 496 | ASSIGN lo_data_ref->* TO . 497 | r_json = dump_int( data = type_descr = lo_typedesc ). 498 | ELSE. 499 | lo_obj_ref ?= data. 500 | lo_classdesc ?= cl_abap_typedescr=>describe_by_object_ref( lo_obj_ref ). 501 | lt_symbols = get_symbols( type_descr = lo_classdesc object = lo_obj_ref ). 502 | r_json = dump_symbols( lt_symbols ). 503 | ENDIF. 504 | 505 | WHEN cl_abap_typedescr=>kind_elem. 506 | lo_elem_descr ?= type_descr. 507 | dump_type data lo_elem_descr r_json. 508 | 509 | WHEN cl_abap_typedescr=>kind_struct. 510 | 511 | lo_structdesc ?= type_descr. 512 | GET REFERENCE OF data INTO lo_data_ref. 513 | lt_symbols = get_symbols( type_descr = lo_structdesc data = lo_data_ref ). 514 | r_json = dump_symbols( lt_symbols ). 515 | 516 | WHEN cl_abap_typedescr=>kind_table. 517 | 518 | lo_tabledescr ?= type_descr. 519 | lo_typedesc = lo_tabledescr->get_table_line_type( ). 520 | 521 | ASSIGN data TO
. 522 | 523 | " optimization for structured tables 524 | IF lo_typedesc->kind EQ cl_abap_typedescr=>kind_struct. 525 | lo_structdesc ?= lo_typedesc. 526 | CREATE DATA lo_data_ref LIKE LINE OF
. 527 | ASSIGN lo_data_ref->* TO . 528 | lt_symbols = get_symbols( type_descr = lo_structdesc data = lo_data_ref ). 529 | 530 | " here we have differentiation of output of simple table to JSON array 531 | " and sorted or hashed table with unique key into JSON associative array 532 | IF lo_tabledescr->has_unique_key IS NOT INITIAL AND mv_assoc_arrays IS NOT INITIAL. 533 | 534 | IF lo_tabledescr->key_defkind EQ lo_tabledescr->keydefkind_user. 535 | LOOP AT lo_tabledescr->key ASSIGNING . 536 | READ TABLE lt_symbols WITH KEY name = -name ASSIGNING . 537 | APPEND TO lt_keys. 538 | ENDLOOP. 539 | ENDIF. 540 | 541 | IF LINES( lo_tabledescr->key ) EQ 1. 542 | READ TABLE lo_tabledescr->key INDEX 1 INTO ls_skip_key. 543 | DELETE lt_symbols WHERE name EQ ls_skip_key-name. 544 | " remove object wrapping for simple name-value tables 545 | IF mv_assoc_arrays_opt EQ abap_true AND LINES( lt_symbols ) EQ 1. 546 | lv_array_opt = abap_true. 547 | ENDIF. 548 | ENDIF. 549 | 550 | LOOP AT
INTO . 551 | CLEAR: lt_fields, lv_prop_name. 552 | LOOP AT lt_symbols ASSIGNING . 553 | ASSIGN -value->* TO . 554 | IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. 555 | IF -type->kind EQ cl_abap_typedescr=>kind_elem. 556 | lo_elem_descr ?= -type. 557 | dump_type lo_elem_descr lv_itemval. 558 | ELSE. 559 | lv_itemval = dump_int( data = type_descr = -type ). 560 | ENDIF. 561 | IF lv_array_opt EQ abap_false. 562 | CONCATENATE -header lv_itemval INTO lv_itemval. 563 | ENDIF. 564 | APPEND lv_itemval TO lt_fields. 565 | ENDIF. 566 | ENDLOOP. 567 | 568 | IF lo_tabledescr->key_defkind EQ lo_tabledescr->keydefkind_user. 569 | LOOP AT lt_keys ASSIGNING . 570 | ASSIGN -value->* TO . 571 | MOVE TO lv_keyval. 572 | CONDENSE lv_keyval. 573 | IF lv_prop_name IS NOT INITIAL. 574 | CONCATENATE lv_prop_name mc_key_separator lv_keyval INTO lv_prop_name. 575 | ELSE. 576 | lv_prop_name = lv_keyval. 577 | ENDIF. 578 | ENDLOOP. 579 | ELSE. 580 | LOOP AT lt_symbols ASSIGNING . 581 | ASSIGN -value->* TO . 582 | MOVE TO lv_keyval. 583 | CONDENSE lv_keyval. 584 | IF lv_prop_name IS NOT INITIAL. 585 | CONCATENATE lv_prop_name mc_key_separator lv_keyval INTO lv_prop_name. 586 | ELSE. 587 | lv_prop_name = lv_keyval. 588 | ENDIF. 589 | ENDLOOP. 590 | ENDIF. 591 | 592 | CONCATENATE LINES OF lt_fields INTO lv_itemval SEPARATED BY `,`. 593 | IF lv_array_opt EQ abap_false. 594 | CONCATENATE `"` lv_prop_name `":{` lv_itemval `}` INTO lv_itemval. 595 | ELSE. 596 | CONCATENATE `"` lv_prop_name `":` lv_itemval `` INTO lv_itemval. 597 | ENDIF. 598 | APPEND lv_itemval TO lt_properties. 599 | 600 | ENDLOOP. 601 | 602 | CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`. 603 | CONCATENATE `{` r_json `}` INTO r_json. 604 | 605 | ELSE. 606 | 607 | LOOP AT
INTO . 608 | CLEAR lt_fields. 609 | LOOP AT lt_symbols ASSIGNING . 610 | ASSIGN -value->* TO . 611 | IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. 612 | IF -type->kind EQ cl_abap_typedescr=>kind_elem. 613 | lo_elem_descr ?= -type. 614 | dump_type lo_elem_descr lv_itemval. 615 | ELSE. 616 | lv_itemval = dump_int( data = type_descr = -type ). 617 | ENDIF. 618 | CONCATENATE -header lv_itemval INTO lv_itemval. 619 | APPEND lv_itemval TO lt_fields. 620 | ENDIF. 621 | ENDLOOP. 622 | 623 | CONCATENATE LINES OF lt_fields INTO lv_itemval SEPARATED BY `,`. 624 | CONCATENATE `{` lv_itemval `}` INTO lv_itemval. 625 | APPEND lv_itemval TO lt_properties. 626 | ENDLOOP. 627 | 628 | CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`. 629 | CONCATENATE `[` r_json `]` INTO r_json. 630 | 631 | ENDIF. 632 | ELSE. 633 | LOOP AT
ASSIGNING . 634 | lv_itemval = dump_int( data = type_descr = lo_typedesc ). 635 | APPEND lv_itemval TO lt_properties. 636 | ENDLOOP. 637 | 638 | CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`. 639 | CONCATENATE `[` r_json `]` INTO r_json. 640 | ENDIF. 641 | 642 | ENDCASE. 643 | 644 | ENDMETHOD. "dump 645 | 646 | 647 | METHOD DUMP_SYMBOLS. 648 | 649 | DATA: lv_properties TYPE STANDARD TABLE OF string, 650 | lv_itemval TYPE string. 651 | 652 | FIELD-SYMBOLS: TYPE ANY, 653 | LIKE LINE OF it_symbols. 654 | 655 | LOOP AT it_symbols ASSIGNING . 656 | ASSIGN -value->* TO . 657 | IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. 658 | lv_itemval = dump_int( data = type_descr = -type ). 659 | CONCATENATE -header lv_itemval INTO lv_itemval. 660 | APPEND lv_itemval TO lv_properties. 661 | ENDIF. 662 | ENDLOOP. 663 | 664 | CONCATENATE LINES OF lv_properties INTO r_json SEPARATED BY `,`. 665 | CONCATENATE `{` r_json `}` INTO r_json. 666 | 667 | ENDMETHOD. 668 | 669 | 670 | METHOD DUMP_TYPE. 671 | 672 | CASE type_descr->type_kind. 673 | WHEN cl_abap_typedescr=>typekind_float OR cl_abap_typedescr=>typekind_int OR cl_abap_typedescr=>typekind_int1 OR 674 | cl_abap_typedescr=>typekind_int2 OR cl_abap_typedescr=>typekind_packed OR `8`. " TYPEKIND_INT8 -> '8' only from 7.40 675 | 676 | IF type_descr->type_kind EQ cl_abap_typedescr=>typekind_packed AND mv_ts_as_iso8601 EQ c_bool-true AND type_descr->absolute_name CP `\TYPE=TIMESTAMP*`. 677 | IF data IS INITIAL. 678 | r_json = `""`. 679 | ELSE. 680 | MOVE data TO r_json. 681 | IF type_descr->absolute_name EQ `\TYPE=TIMESTAMP`. 682 | CONCATENATE `"` r_json(4) `-` r_json+4(2) `-` r_json+6(2) `T` r_json+8(2) `:` r_json+10(2) `:` r_json+12(2) `.0000000Z"` INTO r_json. 683 | ELSEIF type_descr->absolute_name EQ `\TYPE=TIMESTAMPL`. 684 | CONCATENATE `"` r_json(4) `-` r_json+4(2) `-` r_json+6(2) `T` r_json+8(2) `:` r_json+10(2) `:` r_json+12(2) `.` r_json+15(7) `Z"` INTO r_json. 685 | ENDIF. 686 | ENDIF. 687 | ELSEIF data IS INITIAL. 688 | r_json = `0`. 689 | ELSE. 690 | MOVE data TO r_json. 691 | IF data LT 0. 692 | IF type_descr->type_kind <> cl_abap_typedescr=>typekind_float. "float: sign is already at the beginning 693 | SHIFT r_json RIGHT CIRCULAR. 694 | ENDIF. 695 | ELSE. 696 | CONDENSE r_json. 697 | ENDIF. 698 | ENDIF. 699 | WHEN cl_abap_typedescr=>typekind_num. 700 | IF mv_numc_as_string EQ abap_true. 701 | IF data IS INITIAL. 702 | r_json = `""`. 703 | ELSE. 704 | CONCATENATE `"` data `"` INTO r_json. 705 | ENDIF. 706 | ELSE. 707 | IF data IS INITIAL. 708 | r_json = `0`. 709 | ELSE. 710 | MOVE data TO r_json. 711 | SHIFT r_json LEFT DELETING LEADING ` 0`. 712 | ENDIF. 713 | ENDIF. 714 | WHEN cl_abap_typedescr=>typekind_string OR cl_abap_typedescr=>typekind_csequence OR cl_abap_typedescr=>typekind_clike. 715 | IF data IS INITIAL. 716 | r_json = `""`. 717 | ELSEIF type_descr->absolute_name EQ mc_json_type. 718 | r_json = data. 719 | ELSE. 720 | r_json = escape( data ). 721 | CONCATENATE `"` r_json `"` INTO r_json. 722 | ENDIF. 723 | WHEN cl_abap_typedescr=>typekind_xstring OR cl_abap_typedescr=>typekind_hex. 724 | IF data IS INITIAL. 725 | r_json = `""`. 726 | ELSE. 727 | r_json = xstring_to_string( data ). 728 | r_json = escape( r_json ). 729 | CONCATENATE `"` r_json `"` INTO r_json. 730 | ENDIF. 731 | WHEN cl_abap_typedescr=>typekind_char. 732 | IF type_descr->output_length EQ 1 AND mc_bool_types CS type_descr->absolute_name. 733 | IF data EQ c_bool-true. 734 | r_json = `true`. "#EC NOTEXT 735 | ELSEIF mc_bool_3state CS type_descr->absolute_name AND data IS INITIAL. 736 | r_json = `null`. "#EC NOTEXT 737 | ELSE. 738 | r_json = `false`. "#EC NOTEXT 739 | ENDIF. 740 | ELSE. 741 | r_json = escape( data ). 742 | CONCATENATE `"` r_json `"` INTO r_json. 743 | ENDIF. 744 | WHEN cl_abap_typedescr=>typekind_date. 745 | CONCATENATE `"` data(4) `-` data+4(2) `-` data+6(2) `"` INTO r_json. 746 | WHEN cl_abap_typedescr=>typekind_time. 747 | CONCATENATE `"` data(2) `:` data+2(2) `:` data+4(2) `"` INTO r_json. 748 | WHEN OTHERS. 749 | IF data IS INITIAL. 750 | r_json = `null`. "#EC NOTEXT 751 | ELSE. 752 | MOVE data TO r_json. 753 | ENDIF. 754 | ENDCASE. 755 | 756 | ENDMETHOD. "dump_type 757 | 758 | 759 | METHOD DUMP_TYPE_EX. 760 | 761 | DATA: lo_descr TYPE REF TO cl_abap_elemdescr. 762 | lo_descr ?= cl_abap_typedescr=>describe_by_data( data ). 763 | r_json = dump_type( data = data type_descr = lo_descr ). 764 | 765 | ENDMETHOD. "DUMP_TYPE_EX 766 | 767 | 768 | METHOD EDM_DATETIME_TO_TS. 769 | 770 | DATA: lv_ticks TYPE p, 771 | lv_timestamp TYPE timestamp VALUE `19700101000000`. 772 | 773 | lv_ticks = ticks. 774 | lv_ticks = lv_ticks / 1000. " in seconds 775 | lv_timestamp = cl_abap_tstmp=>add( tstmp = lv_timestamp secs = lv_ticks ). 776 | 777 | IF offset IS NOT INITIAL. 778 | lv_ticks = offset+1. 779 | lv_ticks = lv_ticks * 60. "offset is in minutes 780 | IF offset(1) = '+'. 781 | lv_timestamp = cl_abap_tstmp=>subtractsecs( tstmp = lv_timestamp secs = lv_ticks ). 782 | ELSE. 783 | lv_timestamp = cl_abap_tstmp=>add( tstmp = lv_timestamp secs = lv_ticks ). 784 | ENDIF. 785 | ENDIF. 786 | 787 | CASE typekind. 788 | WHEN cl_abap_typedescr=>typekind_time. 789 | r_data = lv_timestamp. 790 | r_data = r_data+8(6). 791 | WHEN cl_abap_typedescr=>typekind_date. 792 | r_data = lv_timestamp. 793 | r_data = r_data(8). 794 | WHEN cl_abap_typedescr=>typekind_packed. 795 | r_data = lv_timestamp. 796 | ENDCASE. 797 | 798 | ENDMETHOD. 799 | 800 | 801 | METHOD ESCAPE. 802 | 803 | MOVE in TO out. 804 | 805 | REPLACE ALL OCCURRENCES OF `\` IN out WITH `\\`. 806 | REPLACE ALL OCCURRENCES OF `"` IN out WITH `\"`. 807 | 808 | ENDMETHOD. "escape 809 | 810 | 811 | METHOD GENERATE. 812 | 813 | DATA: lo_json TYPE REF TO ZUI2_JSON, 814 | lv_json LIKE json. 815 | 816 | lv_json = json. 817 | 818 | REPLACE ALL OCCURRENCES OF `\r\n` IN lv_json WITH cl_abap_char_utilities=>cr_lf. 819 | REPLACE ALL OCCURRENCES OF `\n` IN lv_json WITH cl_abap_char_utilities=>newline. 820 | REPLACE ALL OCCURRENCES OF `\t` IN lv_json WITH cl_abap_char_utilities=>horizontal_tab. 821 | 822 | CREATE OBJECT lo_json 823 | EXPORTING 824 | pretty_name = pretty_name 825 | name_mappings = name_mappings 826 | assoc_arrays = c_bool-true 827 | assoc_arrays_opt = c_bool-true. 828 | 829 | TRY . 830 | rr_data = lo_json->generate_int( lv_json ). 831 | CATCH cx_sy_move_cast_error. 832 | ENDTRY. 833 | 834 | ENDMETHOD. 835 | 836 | 837 | METHOD generate_int. 838 | 839 | TYPES: BEGIN OF ts_field, 840 | name TYPE string, 841 | value TYPE json, 842 | END OF ts_field. 843 | 844 | DATA: length TYPE i, 845 | offset TYPE i. 846 | 847 | DATA: lt_json TYPE STANDARD TABLE OF json WITH DEFAULT KEY, 848 | lv_json LIKE LINE OF lt_json, 849 | lv_comp_name TYPE abap_compname, 850 | lt_fields TYPE HASHED TABLE OF ts_field WITH UNIQUE KEY name, 851 | lo_type TYPE REF TO cl_abap_datadescr, 852 | lt_comp TYPE abap_component_tab, 853 | lt_names TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line, 854 | cache LIKE LINE OF mt_name_mappings_ex, 855 | ls_comp LIKE LINE OF lt_comp. 856 | 857 | FIELD-SYMBOLS: TYPE any, 858 | TYPE any, 859 | LIKE LINE OF lt_fields, 860 |
TYPE STANDARD TABLE, 861 | LIKE LINE OF mt_name_mappings_ex. 862 | 863 | length = numofchar( json ). 864 | 865 | eat_white. 866 | 867 | CASE json+offset(1). 868 | WHEN `{`."result must be a structure 869 | restore_type( EXPORTING json = json length = length CHANGING data = lt_fields ). 870 | IF lt_fields IS NOT INITIAL. 871 | ls_comp-type = cl_abap_refdescr=>get_ref_to_data( ). 872 | LOOP AT lt_fields ASSIGNING . 873 | READ TABLE mt_name_mappings_ex WITH TABLE KEY json = -name ASSIGNING . 874 | IF sy-subrc IS INITIAL. 875 | ls_comp-name = -abap. 876 | ELSE. 877 | cache-json = ls_comp-name = -name. 878 | TRANSLATE ls_comp-name USING `/_:_~_._-_`. " remove characters not allowed in component names 879 | CASE mv_pretty_name. 880 | WHEN pretty_mode-camel_case OR pretty_mode-extended. 881 | REPLACE ALL OCCURRENCES OF REGEX `([a-z])([A-Z])` IN ls_comp-name WITH `$1_$2`. "#EC NOTEXT 882 | WHEN pretty_mode-case_sensitive. 883 | REPLACE ALL OCCURRENCES OF REGEX `([A-Z])` IN ls_comp-name WITH `_$1`. "#EC NOTEXT 884 | ENDCASE. 885 | TRANSLATE ls_comp-name TO UPPER CASE. 886 | cache-abap = ls_comp-name = lv_comp_name = ls_comp-name. " truncate by allowed field name length 887 | INSERT cache INTO TABLE mt_name_mappings_ex. 888 | ENDIF. 889 | INSERT ls_comp-name INTO TABLE lt_names. 890 | IF sy-subrc IS INITIAL. 891 | APPEND ls_comp TO lt_comp. 892 | ELSE. 893 | DELETE lt_fields WHERE name = -name. 894 | ENDIF. 895 | ENDLOOP. 896 | TRY. 897 | lo_type = cl_abap_structdescr=>create( p_components = lt_comp p_strict = c_bool-false ). 898 | CREATE DATA rr_data TYPE HANDLE lo_type. 899 | ASSIGN rr_data->* TO . 900 | DATA: l_index TYPE i. 901 | l_index = 0. 902 | LOOP AT lt_fields ASSIGNING . 903 | l_index = l_index + 1. 904 | ASSIGN COMPONENT l_index OF STRUCTURE TO . 905 | = generate_int( -value ). 906 | ENDLOOP. 907 | CATCH cx_sy_create_data_error cx_sy_struct_creation. 908 | ENDTRY. 909 | ENDIF. 910 | WHEN `[`."result must be a table of ref 911 | restore_type( EXPORTING json = json length = length CHANGING data = lt_json ). 912 | CREATE DATA rr_data TYPE TABLE OF REF TO data. 913 | ASSIGN rr_data->* TO
. 914 | LOOP AT lt_json INTO lv_json. 915 | APPEND INITIAL LINE TO
ASSIGNING . 916 | = generate_int( lv_json ). 917 | ENDLOOP. 918 | WHEN OTHERS. 919 | IF json+offset(1) EQ `"`. 920 | CREATE DATA rr_data TYPE string. 921 | ELSEIF json+offset(1) CA `-0123456789.`. 922 | IF json+offset CS '.'. 923 | CREATE DATA rr_data TYPE f. 924 | ELSEIF length GT 9. 925 | CREATE DATA rr_data TYPE p LENGTH 16. 926 | ELSE. 927 | CREATE DATA rr_data TYPE i. 928 | ENDIF. 929 | ELSEIF json+offset EQ `true` OR json+offset EQ `false`. 930 | CREATE DATA rr_data TYPE abap_bool. 931 | ENDIF. 932 | IF rr_data IS BOUND. 933 | ASSIGN rr_data->* TO . 934 | restore_type( EXPORTING json = json length = length CHANGING data = ). 935 | ENDIF. 936 | ENDCASE. 937 | 938 | ENDMETHOD. 939 | 940 | 941 | METHOD GENERATE_INT_EX. 942 | 943 | DATA: lv_assoc_arrays LIKE mv_assoc_arrays, 944 | lv_assoc_arrays_opt LIKE mv_assoc_arrays_opt, 945 | lv_mark LIKE offset, 946 | lv_match LIKE lv_mark, 947 | lv_json TYPE ZUI2_JSON=>json. 948 | 949 | lv_mark = offset. 950 | restore_type( EXPORTING json = json length = length CHANGING offset = offset ). 951 | lv_match = offset - lv_mark. 952 | lv_json = json+lv_mark(lv_match). 953 | 954 | lv_assoc_arrays = mv_assoc_arrays. 955 | lv_assoc_arrays_opt = mv_assoc_arrays_opt. 956 | 957 | mv_assoc_arrays = abap_true. 958 | mv_assoc_arrays_opt = abap_true. 959 | 960 | data = generate_int( lv_json ). 961 | 962 | mv_assoc_arrays = lv_assoc_arrays. 963 | mv_assoc_arrays_opt = lv_assoc_arrays_opt. 964 | 965 | ENDMETHOD. 966 | 967 | 968 | METHOD GET_FIELDS. 969 | 970 | DATA: lt_symbols TYPE t_t_symbol, 971 | lv_name TYPE char128, 972 | ls_field LIKE LINE OF rt_fields. 973 | 974 | FIELD-SYMBOLS: LIKE LINE OF lt_symbols, 975 | LIKE LINE OF mt_name_mappings. 976 | 977 | lt_symbols = get_symbols( type_descr = type_descr data = data object = object include_aliases = abap_true ). 978 | 979 | LOOP AT lt_symbols ASSIGNING WHERE read_only EQ abap_false. 980 | ls_field-name = -name. 981 | ls_field-type = -type. 982 | ls_field-value = -value. 983 | 984 | " insert as UPPER CASE 985 | INSERT ls_field INTO TABLE rt_fields. 986 | 987 | " insert as lower case 988 | TRANSLATE ls_field-name TO LOWER CASE. 989 | INSERT ls_field INTO TABLE rt_fields. 990 | 991 | " as pretty printed 992 | IF mv_pretty_name NE pretty_mode-none AND mv_pretty_name NE pretty_mode-low_case. 993 | format_name -name mv_pretty_name ls_field-name. 994 | INSERT ls_field INTO TABLE rt_fields. 995 | " let us check for not well formed canelCase to be compatible with old logic 996 | lv_name = ls_field-name. 997 | TRANSLATE lv_name(1) TO UPPER CASE. 998 | ls_field-name = lv_name. 999 | INSERT ls_field INTO TABLE rt_fields. 1000 | ENDIF. 1001 | 1002 | ENDLOOP. 1003 | 1004 | ENDMETHOD. 1005 | 1006 | 1007 | METHOD GET_SYMBOLS. 1008 | 1009 | DATA: comp_tab TYPE cl_abap_structdescr=>component_table, 1010 | symb_tab LIKE result, 1011 | symb LIKE LINE OF symb_tab, 1012 | class_descr TYPE REF TO cl_abap_classdescr, 1013 | struct_descr TYPE REF TO cl_abap_structdescr. 1014 | 1015 | FIELD-SYMBOLS: LIKE LINE OF comp_tab, 1016 | LIKE LINE OF cl_abap_objectdescr=>attributes, 1017 | LIKE LINE OF mt_name_mappings, 1018 | TYPE any. 1019 | 1020 | IF type_descr->kind EQ cl_abap_typedescr=>kind_struct. 1021 | 1022 | struct_descr ?= type_descr. 1023 | comp_tab = struct_descr->get_components( ). 1024 | 1025 | LOOP AT comp_tab ASSIGNING . 1026 | IF -name IS NOT INITIAL AND 1027 | ( -as_include EQ abap_false OR include_aliases EQ abap_true OR mv_expand_includes EQ abap_false ). 1028 | symb-name = -name. 1029 | symb-type = -type. 1030 | IF data IS BOUND. 1031 | is_compressable symb-type symb-name symb-compressable. 1032 | ASSIGN data->(symb-name) TO . 1033 | GET REFERENCE OF INTO symb-value. 1034 | format_name symb-name mv_pretty_name symb-header. 1035 | CONCATENATE `"` symb-header `":` INTO symb-header. 1036 | ENDIF. 1037 | APPEND symb TO result. 1038 | ENDIF. 1039 | IF -as_include EQ abap_true AND mv_expand_includes EQ abap_true. 1040 | struct_descr ?= -type. 1041 | symb_tab = get_symbols( type_descr = struct_descr include_aliases = include_aliases ). 1042 | LOOP AT symb_tab INTO symb. 1043 | CONCATENATE symb-name -suffix INTO symb-name. 1044 | IF data IS BOUND. 1045 | is_compressable symb-type symb-name symb-compressable. 1046 | ASSIGN data->(symb-name) TO . 1047 | GET REFERENCE OF INTO symb-value. 1048 | format_name symb-name mv_pretty_name symb-header. 1049 | CONCATENATE `"` symb-header `":` INTO symb-header. 1050 | ENDIF. 1051 | APPEND symb TO result. 1052 | ENDLOOP. 1053 | ENDIF. 1054 | ENDLOOP. 1055 | 1056 | ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_class. 1057 | 1058 | class_descr ?= type_descr. 1059 | LOOP AT class_descr->attributes ASSIGNING WHERE is_constant IS INITIAL AND alias_for IS INITIAL AND 1060 | ( is_interface IS INITIAL OR type_kind NE cl_abap_typedescr=>typekind_oref ). 1061 | ASSIGN object->(-name) TO . 1062 | CHECK sy-subrc IS INITIAL. " we can only assign to public attributes 1063 | symb-name = -name. 1064 | symb-read_only = -is_read_only. 1065 | symb-type = class_descr->get_attribute_type( -name ). 1066 | is_compressable symb-type symb-name symb-compressable. 1067 | GET REFERENCE OF INTO symb-value. 1068 | format_name symb-name mv_pretty_name symb-header. 1069 | CONCATENATE `"` symb-header `":` INTO symb-header. 1070 | APPEND symb TO result. 1071 | ENDLOOP. 1072 | 1073 | ENDIF. 1074 | 1075 | ENDMETHOD. "GET_SYMBOLS 1076 | 1077 | 1078 | METHOD IS_COMPRESSABLE. 1079 | rv_compress = abap_true. 1080 | ENDMETHOD. 1081 | 1082 | 1083 | METHOD PRETTY_NAME. 1084 | 1085 | DATA: tokens TYPE TABLE OF char128, 1086 | cache LIKE LINE OF mt_name_mappings. 1087 | 1088 | FIELD-SYMBOLS: LIKE LINE OF tokens, 1089 | LIKE LINE OF mt_name_mappings. 1090 | 1091 | READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING . 1092 | IF sy-subrc IS INITIAL. 1093 | out = -json. 1094 | ELSE. 1095 | out = in. 1096 | 1097 | REPLACE ALL OCCURRENCES OF `__` IN out WITH `*`. 1098 | 1099 | TRANSLATE out TO LOWER CASE. 1100 | TRANSLATE out USING `/_:_~_`. 1101 | SPLIT out AT `_` INTO TABLE tokens. 1102 | LOOP AT tokens ASSIGNING FROM 2. 1103 | TRANSLATE (1) TO UPPER CASE. 1104 | ENDLOOP. 1105 | 1106 | CONCATENATE LINES OF tokens INTO out. 1107 | REPLACE ALL OCCURRENCES OF `*` IN out WITH `_`. 1108 | 1109 | cache-abap = in. 1110 | cache-json = out. 1111 | INSERT cache INTO TABLE mt_name_mappings. 1112 | INSERT cache INTO TABLE mt_name_mappings_ex. 1113 | ENDIF. 1114 | 1115 | ENDMETHOD. "pretty_name 1116 | 1117 | 1118 | METHOD PRETTY_NAME_EX. 1119 | 1120 | DATA: tokens TYPE TABLE OF char128, 1121 | cache LIKE LINE OF mt_name_mappings, 1122 | lt_match TYPE match_result_tab. 1123 | 1124 | FIELD-SYMBOLS: LIKE LINE OF tokens, 1125 | LIKE LINE OF mt_name_mappings, 1126 | LIKE LINE OF lt_match, 1127 | TYPE LINE OF submatch_result_tab. 1128 | 1129 | READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING . 1130 | IF sy-subrc IS INITIAL. 1131 | out = -json. 1132 | ELSE. 1133 | out = in. 1134 | 1135 | 1136 | TRANSLATE out TO LOWER CASE. 1137 | TRANSLATE out USING `/_:_~_`. 1138 | 1139 | REPLACE ALL OCCURRENCES OF `__e__` IN out WITH `!`. 1140 | REPLACE ALL OCCURRENCES OF `__n__` IN out WITH `#`. 1141 | REPLACE ALL OCCURRENCES OF `__d__` IN out WITH `$`. 1142 | REPLACE ALL OCCURRENCES OF `__p__` IN out WITH `%`. 1143 | REPLACE ALL OCCURRENCES OF `__m__` IN out WITH `&`. 1144 | REPLACE ALL OCCURRENCES OF `__s__` IN out WITH `*`. 1145 | REPLACE ALL OCCURRENCES OF `__h__` IN out WITH `-`. 1146 | REPLACE ALL OCCURRENCES OF `__t__` IN out WITH `~`. 1147 | REPLACE ALL OCCURRENCES OF `__l__` IN out WITH `/`. 1148 | REPLACE ALL OCCURRENCES OF `__c__` IN out WITH `:`. 1149 | REPLACE ALL OCCURRENCES OF `__v__` IN out WITH `|`. 1150 | REPLACE ALL OCCURRENCES OF `__a__` IN out WITH `@`. 1151 | REPLACE ALL OCCURRENCES OF `__o__` IN out WITH `.`. 1152 | REPLACE ALL OCCURRENCES OF `___` IN out WITH `.`. 1153 | 1154 | REPLACE ALL OCCURRENCES OF `__` IN out WITH `"`. 1155 | 1156 | SPLIT out AT `_` INTO TABLE tokens. 1157 | LOOP AT tokens ASSIGNING FROM 2. 1158 | TRANSLATE (1) TO UPPER CASE. 1159 | ENDLOOP. 1160 | 1161 | CONCATENATE LINES OF tokens INTO out. 1162 | REPLACE ALL OCCURRENCES OF `"` IN out WITH `_`. 1163 | 1164 | cache-abap = in. 1165 | cache-json = out. 1166 | INSERT cache INTO TABLE mt_name_mappings. 1167 | INSERT cache INTO TABLE mt_name_mappings_ex. 1168 | ENDIF. 1169 | 1170 | ENDMETHOD. "pretty_name_ex 1171 | 1172 | 1173 | METHOD RAW_TO_STRING. 1174 | 1175 | DATA: lv_output_length TYPE i, 1176 | lt_binary_tab TYPE STANDARD TABLE OF sdokcntbin. 1177 | 1178 | CALL FUNCTION 'SCMS_XSTRING_TO_BINARY' 1179 | EXPORTING 1180 | buffer = iv_xstring 1181 | IMPORTING 1182 | output_length = lv_output_length 1183 | TABLES 1184 | binary_tab = lt_binary_tab. 1185 | 1186 | CALL FUNCTION 'SCMS_BINARY_TO_STRING' 1187 | EXPORTING 1188 | input_length = lv_output_length 1189 | encoding = iv_encoding 1190 | IMPORTING 1191 | text_buffer = rv_string 1192 | output_length = lv_output_length 1193 | TABLES 1194 | binary_tab = lt_binary_tab. 1195 | 1196 | ENDMETHOD. 1197 | 1198 | 1199 | METHOD RESTORE. 1200 | 1201 | DATA: mark LIKE offset, 1202 | match LIKE offset, 1203 | pos LIKE offset, 1204 | unescape TYPE abap_bool, 1205 | ref_descr TYPE REF TO cl_abap_refdescr, 1206 | data_descr TYPE REF TO cl_abap_datadescr, 1207 | data_ref TYPE REF TO data, 1208 | object_ref TYPE REF TO object, 1209 | fields LIKE field_cache, 1210 | name_json TYPE string. 1211 | 1212 | FIELD-SYMBOLS: TYPE ANY, 1213 | LIKE LINE OF field_cache. 1214 | 1215 | fields = field_cache. 1216 | 1217 | IF type_descr IS NOT INITIAL AND type_descr->kind EQ type_descr->kind_ref. 1218 | ref_descr ?= type_descr. 1219 | type_descr = ref_descr->get_referenced_type( ). 1220 | IF ref_descr->type_kind EQ ref_descr->typekind_oref. 1221 | IF data IS INITIAL. 1222 | " can fire an exception, if type is abstract or constructor protected 1223 | CREATE OBJECT data TYPE (type_descr->absolute_name). 1224 | ENDIF. 1225 | object_ref ?= data. 1226 | fields = get_fields( type_descr = type_descr object = object_ref ). 1227 | ELSEIF ref_descr->type_kind EQ ref_descr->typekind_dref. 1228 | IF data IS INITIAL. 1229 | data_descr ?= type_descr. 1230 | CREATE DATA data TYPE HANDLE data_descr. 1231 | ENDIF. 1232 | data_ref ?= data. 1233 | ASSIGN data_ref->* TO . 1234 | fields = get_fields( type_descr = type_descr data = data_ref ). 1235 | restore( EXPORTING json = json length = length type_descr = type_descr field_cache = fields 1236 | CHANGING data = offset = offset ). 1237 | RETURN. 1238 | ENDIF. 1239 | ENDIF. 1240 | 1241 | IF fields IS INITIAL AND type_descr IS NOT INITIAL AND type_descr->kind EQ type_descr->kind_struct. 1242 | GET REFERENCE OF data INTO data_ref. 1243 | fields = get_fields( type_descr = type_descr data = data_ref ). 1244 | ENDIF. 1245 | 1246 | eat_white. 1247 | eat_char `{`. 1248 | eat_white. 1249 | 1250 | WHILE offset < length AND json+offset(1) NE `}`. 1251 | 1252 | eat_white. 1253 | eat_string name_json. 1254 | eat_white. 1255 | eat_char `:`. 1256 | eat_white. 1257 | 1258 | READ TABLE fields WITH TABLE KEY name = name_json ASSIGNING . 1259 | IF sy-subrc IS NOT INITIAL. 1260 | TRANSLATE name_json TO UPPER CASE. 1261 | READ TABLE fields WITH TABLE KEY name = name_json ASSIGNING . 1262 | ENDIF. 1263 | 1264 | IF sy-subrc IS INITIAL. 1265 | ASSIGN -value->* TO . 1266 | restore_type( EXPORTING json = json length = length type_descr = -type CHANGING data = offset = offset ). 1267 | ELSE. 1268 | restore_type( EXPORTING json = json length = length CHANGING offset = offset ). 1269 | ENDIF. 1270 | 1271 | eat_white. 1272 | 1273 | IF offset < length AND json+offset(1) NE `}`. 1274 | eat_char `,`. 1275 | ELSE. 1276 | EXIT. 1277 | ENDIF. 1278 | 1279 | ENDWHILE. 1280 | 1281 | eat_char `}`. 1282 | 1283 | ENDMETHOD. "restore 1284 | 1285 | 1286 | METHOD RESTORE_TYPE. 1287 | 1288 | DATA: mark LIKE offset, 1289 | match LIKE offset, 1290 | unescape TYPE abap_bool, 1291 | sdummy TYPE string, "#EC NEEDED 1292 | lr_idummy TYPE REF TO i, "#EC NEEDED 1293 | lr_bdummy TYPE REF TO bool, "#EC NEEDED 1294 | lr_sdummy TYPE REF TO string, "#EC NEEDED 1295 | pos LIKE offset, 1296 | line TYPE REF TO data, 1297 | key_ref TYPE REF TO data, 1298 | data_ref TYPE REF TO data, 1299 | key_name TYPE string, 1300 | key_value TYPE string, 1301 | lt_fields LIKE field_cache, 1302 | lt_symbols TYPE t_t_symbol, 1303 | lv_ticks TYPE string, 1304 | lv_offset TYPE string, 1305 | lo_exp TYPE REF TO cx_root, 1306 | elem_descr TYPE REF TO cl_abap_elemdescr, 1307 | table_descr TYPE REF TO cl_abap_tabledescr, 1308 | data_descr TYPE REF TO cl_abap_datadescr. 1309 | 1310 | FIELD-SYMBOLS: TYPE any, 1311 | TYPE any, 1312 | TYPE data, 1313 | LIKE LINE OF lt_fields, 1314 |
TYPE ANY TABLE, 1315 | LIKE LINE OF lt_symbols. 1316 | 1317 | IF type_descr IS INITIAL AND data IS SUPPLIED. 1318 | type_descr = cl_abap_typedescr=>describe_by_data( data ). 1319 | ENDIF. 1320 | 1321 | eat_white. 1322 | 1323 | TRY . 1324 | IF type_descr IS NOT INITIAL AND type_descr->absolute_name EQ mc_json_type. 1325 | " skip deserialization 1326 | mark = offset. 1327 | restore_type( EXPORTING json = json length = length CHANGING offset = offset ). 1328 | match = offset - mark. 1329 | data = json+mark(match). 1330 | ENDIF. 1331 | 1332 | CASE json+offset(1). 1333 | WHEN `{`. " object 1334 | IF type_descr IS NOT INITIAL. 1335 | IF mv_assoc_arrays EQ c_bool-true AND type_descr->kind EQ cl_abap_typedescr=>kind_table. 1336 | table_descr ?= type_descr. 1337 | data_descr = table_descr->get_table_line_type( ). 1338 | IF table_descr->has_unique_key IS NOT INITIAL. 1339 | eat_char `{`. 1340 | eat_white. 1341 | IF json+offset(1) NE `}`. 1342 | ASSIGN data TO
. 1343 | CLEAR
. 1344 | CREATE DATA line LIKE LINE OF
. 1345 | ASSIGN line->* TO . 1346 | lt_fields = get_fields( type_descr = data_descr data = line ). 1347 | IF table_descr->key_defkind EQ table_descr->keydefkind_user AND LINES( table_descr->key ) EQ 1. 1348 | READ TABLE table_descr->key INDEX 1 INTO key_name. 1349 | READ TABLE lt_fields WITH TABLE KEY name = key_name ASSIGNING . 1350 | key_ref = -value. 1351 | IF mv_assoc_arrays_opt EQ c_bool-true. 1352 | lt_symbols = get_symbols( type_descr = data_descr data = line ). 1353 | DELETE lt_symbols WHERE name EQ key_name. 1354 | IF LINES( lt_symbols ) EQ 1. 1355 | READ TABLE lt_symbols INDEX 1 ASSIGNING . 1356 | ENDIF. 1357 | ENDIF. 1358 | ENDIF. 1359 | WHILE offset < length AND json+offset(1) NE `}`. 1360 | CLEAR . 1361 | eat_white. 1362 | eat_string key_value. 1363 | eat_white. 1364 | eat_char `:`. 1365 | eat_white. 1366 | IF IS ASSIGNED. 1367 | ASSIGN -value->* TO . 1368 | restore_type( EXPORTING json = json length = length type_descr = -type 1369 | CHANGING data = offset = offset ). 1370 | ELSE. 1371 | restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fields 1372 | CHANGING data = offset = offset ). 1373 | ENDIF. 1374 | IF table_descr->key_defkind EQ table_descr->keydefkind_user. 1375 | IF key_ref IS BOUND. 1376 | ASSIGN key_ref->* TO . 1377 | IF IS INITIAL. 1378 | MOVE key_value TO . 1379 | ENDIF. 1380 | ENDIF. 1381 | ELSEIF IS INITIAL. 1382 | MOVE key_value TO . 1383 | ENDIF. 1384 | 1385 | INSERT INTO TABLE
. 1386 | eat_white. 1387 | IF offset < length AND json+offset(1) NE `}`. 1388 | eat_char `,`. 1389 | ELSE. 1390 | EXIT. 1391 | ENDIF. 1392 | ENDWHILE. 1393 | ELSE. 1394 | CLEAR data. 1395 | ENDIF. 1396 | eat_char `}`. 1397 | ELSE. 1398 | restore( EXPORTING json = json length = length CHANGING offset = offset ). 1399 | ENDIF. 1400 | ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. 1401 | IF data IS INITIAL. 1402 | generate_int_ex( EXPORTING json = json length = length CHANGING offset = offset data = data ). 1403 | ELSE. 1404 | data_ref ?= data. 1405 | type_descr = cl_abap_typedescr=>describe_by_data_ref( data_ref ). 1406 | ASSIGN data_ref->* TO . 1407 | restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING data = offset = offset ). 1408 | ENDIF. 1409 | ELSE. 1410 | restore( EXPORTING json = json length = length type_descr = type_descr field_cache = field_cache 1411 | CHANGING data = data offset = offset ). 1412 | ENDIF. 1413 | ELSE. 1414 | restore( EXPORTING json = json length = length CHANGING offset = offset ). 1415 | ENDIF. 1416 | WHEN `[`. " array 1417 | IF type_descr IS NOT INITIAL AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. 1418 | IF data IS INITIAL. 1419 | generate_int_ex( EXPORTING json = json length = length CHANGING offset = offset data = data ). 1420 | ELSE. 1421 | data_ref ?= data. 1422 | type_descr = cl_abap_typedescr=>describe_by_data_ref( data_ref ). 1423 | ASSIGN data_ref->* TO . 1424 | restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING data = offset = offset ). 1425 | ENDIF. 1426 | ELSE. 1427 | eat_char `[`. 1428 | eat_white. 1429 | IF json+offset(1) NE `]`. 1430 | IF type_descr IS NOT INITIAL AND type_descr->kind EQ cl_abap_typedescr=>kind_table. 1431 | table_descr ?= type_descr. 1432 | data_descr = table_descr->get_table_line_type( ). 1433 | ASSIGN data TO
. 1434 | CLEAR
. 1435 | CREATE DATA line LIKE LINE OF
. 1436 | ASSIGN line->* TO . 1437 | lt_fields = get_fields( type_descr = data_descr data = line ). 1438 | WHILE offset < length AND json+offset(1) NE `]`. 1439 | CLEAR . 1440 | restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fields 1441 | CHANGING data = offset = offset ). 1442 | INSERT INTO TABLE
. 1443 | eat_white. 1444 | IF offset < length AND json+offset(1) NE `]`. 1445 | eat_char `,`. 1446 | ELSE. 1447 | EXIT. 1448 | ENDIF. 1449 | ENDWHILE. 1450 | ELSE. 1451 | " skip array 1452 | WHILE offset < length AND json+offset(1) NE `}`. 1453 | eat_white. 1454 | restore_type( EXPORTING json = json length = length CHANGING offset = offset ). 1455 | eat_white. 1456 | IF offset < length AND json+offset(1) NE `]`. 1457 | eat_char `,`. 1458 | ELSE. 1459 | EXIT. 1460 | ENDIF. 1461 | ENDWHILE. 1462 | IF type_descr IS NOT INITIAL. 1463 | eat_char `]`. 1464 | throw_error. 1465 | ENDIF. 1466 | ENDIF. 1467 | ELSE. 1468 | CLEAR data. 1469 | ENDIF. 1470 | eat_char `]`. 1471 | ENDIF. 1472 | WHEN `"`. " string 1473 | eat_string sdummy. 1474 | IF type_descr IS NOT INITIAL. 1475 | " unescape string 1476 | IF sdummy IS NOT INITIAL. 1477 | IF type_descr->kind EQ cl_abap_typedescr=>kind_elem. 1478 | elem_descr ?= type_descr. 1479 | CASE elem_descr->type_kind. 1480 | WHEN cl_abap_typedescr=>typekind_char. 1481 | IF elem_descr->output_length EQ 1 AND mc_bool_types CS elem_descr->absolute_name. 1482 | IF sdummy(1) CA `XxTt1`. 1483 | data = c_bool-true. 1484 | ELSE. 1485 | data = c_bool-false. 1486 | ENDIF. 1487 | RETURN. 1488 | ENDIF. 1489 | WHEN cl_abap_typedescr=>typekind_xstring OR cl_abap_typedescr=>typekind_hex. 1490 | string_to_xstring( EXPORTING in = sdummy CHANGING out = data ). 1491 | RETURN. 1492 | WHEN cl_abap_typedescr=>typekind_date. 1493 | " support for ISO8601 => https://en.wikipedia.org/wiki/ISO_8601 1494 | REPLACE FIRST OCCURRENCE OF REGEX `^(\d{4})-(\d{2})-(\d{2})` IN sdummy WITH `$1$2$3` 1495 | REPLACEMENT LENGTH match. "#EC NOTEXT 1496 | IF sy-subrc EQ 0. 1497 | sdummy = sdummy(match). 1498 | ELSE. 1499 | " support for Edm.DateTime => http://www.odata.org/documentation/odata-version-2-0/json-format/ 1500 | FIND FIRST OCCURRENCE OF REGEX `^\/Date\((-?\d+)([+-]\d{1,4})?\)\/` IN sdummy SUBMATCHES lv_ticks lv_offset IGNORING CASE. 1501 | IF sy-subrc EQ 0. 1502 | sdummy = edm_datetime_to_ts( ticks = lv_ticks offset = lv_offset typekind = elem_descr->type_kind ). 1503 | ELSE. 1504 | " support for Edm.Time => https://www.w3.org/TR/xmlschema11-2/#nt-durationRep 1505 | REPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$1$2$3` 1506 | REPLACEMENT LENGTH match. "#EC NOTEXT 1507 | IF sy-subrc EQ 0. 1508 | sdummy = sdummy(match). 1509 | ENDIF. 1510 | ENDIF. 1511 | ENDIF. 1512 | WHEN cl_abap_typedescr=>typekind_time. 1513 | " support for ISO8601 => https://en.wikipedia.org/wiki/ISO_8601 1514 | REPLACE FIRST OCCURRENCE OF REGEX `^(\d{2}):(\d{2}):(\d{2})` IN sdummy WITH `$1$2$3` 1515 | REPLACEMENT LENGTH match. "#EC NOTEXT 1516 | IF sy-subrc EQ 0. 1517 | sdummy = sdummy(match). 1518 | ELSE. 1519 | " support for Edm.DateTime => http://www.odata.org/documentation/odata-version-2-0/json-format/ 1520 | FIND FIRST OCCURRENCE OF REGEX '^\/Date\((-?\d+)([+-]\d{1,4})?\)\/' IN sdummy SUBMATCHES lv_ticks lv_offset IGNORING CASE. 1521 | IF sy-subrc EQ 0. 1522 | sdummy = edm_datetime_to_ts( ticks = lv_ticks offset = lv_offset typekind = elem_descr->type_kind ). 1523 | ELSE. 1524 | " support for Edm.Time => https://www.w3.org/TR/xmlschema11-2/#nt-durationRep 1525 | REPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$4$5$6` 1526 | REPLACEMENT LENGTH match. "#EC NOTEXT 1527 | IF sy-subrc EQ 0. 1528 | sdummy = sdummy(match). 1529 | ENDIF. 1530 | ENDIF. 1531 | ENDIF. 1532 | WHEN cl_abap_typedescr=>typekind_packed. 1533 | REPLACE FIRST OCCURRENCE OF REGEX `^(\d{4})-?(\d{2})-?(\d{2})T(\d{2}):?(\d{2}):?(\d{2})(?:[\.,](\d{0,7}))?Z?` IN sdummy WITH `$1$2$3$4$5$6.$7` 1534 | REPLACEMENT LENGTH match. "#EC NOTEXT 1535 | IF sy-subrc EQ 0. 1536 | sdummy = sdummy(match). 1537 | ELSE. 1538 | FIND FIRST OCCURRENCE OF REGEX '^\/Date\((-?\d+)([+-]\d{1,4})?\)\/' IN sdummy SUBMATCHES lv_ticks lv_offset IGNORING CASE. 1539 | IF sy-subrc EQ 0. 1540 | sdummy = edm_datetime_to_ts( ticks = lv_ticks offset = lv_offset typekind = elem_descr->type_kind ). 1541 | ELSE. 1542 | " support for Edm.Time => https://www.w3.org/TR/xmlschema11-2/#nt-durationRep 1543 | REPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$1$2$3$4$5$6.$7` 1544 | REPLACEMENT LENGTH match. "#EC NOTEXT 1545 | IF sy-subrc EQ 0. 1546 | sdummy = sdummy(match). 1547 | ENDIF. 1548 | ENDIF. 1549 | ENDIF. 1550 | ENDCASE. 1551 | ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. 1552 | CREATE DATA lr_sdummy TYPE string. 1553 | MOVE sdummy TO lr_sdummy->*. 1554 | data ?= lr_sdummy. 1555 | RETURN. 1556 | ELSE. 1557 | throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTED 1558 | ENDIF. 1559 | MOVE sdummy TO data. 1560 | ELSEIF type_descr->kind EQ cl_abap_typedescr=>kind_elem. 1561 | CLEAR data. 1562 | ELSE. 1563 | throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTED 1564 | ENDIF. 1565 | ENDIF. 1566 | WHEN `-`. " number 1567 | IF type_descr IS NOT INITIAL. 1568 | IF type_descr->kind EQ type_descr->kind_ref AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. 1569 | CREATE DATA lr_idummy TYPE i. 1570 | eat_number lr_idummy->*. "#EC NOTEXT 1571 | data ?= lr_idummy. 1572 | ELSEIF type_descr->kind EQ type_descr->kind_elem. 1573 | eat_number data. "#EC NOTEXT 1574 | ELSE. 1575 | eat_number sdummy. "#EC NOTEXT 1576 | throw_error. 1577 | ENDIF. 1578 | ELSE. 1579 | eat_number sdummy. "#EC NOTEXT 1580 | ENDIF. 1581 | WHEN OTHERS. 1582 | FIND FIRST OCCURRENCE OF json+offset(1) IN `0123456789`. 1583 | IF sy-subrc IS INITIAL. " number 1584 | IF type_descr IS NOT INITIAL. 1585 | IF type_descr->kind EQ type_descr->kind_ref AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. 1586 | CREATE DATA lr_idummy TYPE i. 1587 | eat_number lr_idummy->*. "#EC NOTEXT 1588 | data ?= lr_idummy. 1589 | ELSEIF type_descr->kind EQ type_descr->kind_elem. 1590 | eat_number data. "#EC NOTEXT 1591 | ELSE. 1592 | eat_number sdummy. "#EC NOTEXT 1593 | throw_error. 1594 | ENDIF. 1595 | ELSE. 1596 | eat_number sdummy. "#EC NOTEXT 1597 | ENDIF. 1598 | ELSE. " true/false/null 1599 | IF type_descr IS NOT INITIAL. 1600 | IF type_descr->kind EQ type_descr->kind_ref AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. 1601 | CREATE DATA lr_bdummy TYPE bool. 1602 | eat_bool lr_bdummy->*. "#EC NOTEXT 1603 | data ?= lr_bdummy. 1604 | ELSEIF type_descr->kind EQ type_descr->kind_elem. 1605 | eat_bool data. "#EC NOTEXT 1606 | ELSE. 1607 | eat_bool sdummy. "#EC NOTEXT 1608 | throw_error. 1609 | ENDIF. 1610 | ELSE. 1611 | eat_bool sdummy. "#EC NOTEXT 1612 | ENDIF. 1613 | ENDIF. 1614 | ENDCASE. 1615 | CATCH cx_sy_move_cast_error cx_sy_conversion_no_number cx_sy_conversion_overflow INTO lo_exp. 1616 | CLEAR data. 1617 | IF mv_strict_mode EQ abap_true. 1618 | RAISE EXCEPTION TYPE cx_sy_move_cast_error EXPORTING previous = lo_exp. 1619 | ENDIF. 1620 | ENDTRY. 1621 | 1622 | ENDMETHOD. "restore_type 1623 | 1624 | 1625 | METHOD SERIALIZE. 1626 | 1627 | " ********************************************************************** 1628 | "! Usage examples and documentation can be found on SCN: 1629 | " http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer 1630 | " ********************************************************************** " 1631 | 1632 | DATA: lo_json TYPE REF TO ZUI2_JSON. 1633 | 1634 | CREATE OBJECT lo_json 1635 | EXPORTING 1636 | compress = compress 1637 | pretty_name = pretty_name 1638 | name_mappings = name_mappings 1639 | assoc_arrays = assoc_arrays 1640 | assoc_arrays_opt = assoc_arrays_opt 1641 | expand_includes = expand_includes 1642 | numc_as_string = numc_as_string 1643 | ts_as_iso8601 = ts_as_iso8601. 1644 | 1645 | r_json = lo_json->serialize_int( name = name data = data type_descr = type_descr ). 1646 | 1647 | ENDMETHOD. "serialize 1648 | 1649 | 1650 | METHOD SERIALIZE_INT. 1651 | 1652 | " ********************************************************************** 1653 | "! Usage examples and documentation can be found on SCN: 1654 | " http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer 1655 | " ********************************************************************** " 1656 | 1657 | DATA: lo_descr TYPE REF TO cl_abap_typedescr. 1658 | 1659 | IF type_descr IS INITIAL. 1660 | lo_descr = cl_abap_typedescr=>describe_by_data( data ). 1661 | ELSE. 1662 | lo_descr = type_descr. 1663 | ENDIF. 1664 | 1665 | r_json = dump_int( data = data type_descr = lo_descr ). 1666 | 1667 | " we do not do escaping of every single string value for white space characters, 1668 | " but we do it on top, to replace multiple calls by 3 only, while we do not serialize 1669 | " outlined/formatted JSON this shall not produce any harm 1670 | REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN r_json WITH `\r\n`. 1671 | REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline IN r_json WITH `\n`. 1672 | REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab IN r_json WITH `\t`. 1673 | * REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>form_feed IN r_json WITH `\f`. 1674 | * REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>backspace IN r_json WITH `\b`. 1675 | 1676 | IF name IS NOT INITIAL AND ( mv_compress IS INITIAL OR r_json IS NOT INITIAL ). 1677 | CONCATENATE `"` name `":` r_json INTO r_json. 1678 | ENDIF. 1679 | 1680 | ENDMETHOD. "serialize 1681 | 1682 | 1683 | METHOD STRING_TO_RAW. 1684 | 1685 | CALL FUNCTION 'SCMS_STRING_TO_XSTRING' 1686 | EXPORTING 1687 | text = iv_string 1688 | encoding = iv_encoding 1689 | IMPORTING 1690 | buffer = rv_xstring 1691 | EXCEPTIONS 1692 | OTHERS = 1. 1693 | 1694 | IF sy-subrc IS NOT INITIAL. 1695 | CLEAR rv_xstring. 1696 | ENDIF. 1697 | 1698 | ENDMETHOD. 1699 | 1700 | 1701 | METHOD STRING_TO_XSTRING. 1702 | 1703 | DATA: lv_xstring TYPE xstring. 1704 | 1705 | CALL FUNCTION 'SSFC_BASE64_DECODE' 1706 | EXPORTING 1707 | b64data = in 1708 | IMPORTING 1709 | bindata = lv_xstring 1710 | EXCEPTIONS 1711 | OTHERS = 1. 1712 | 1713 | IF sy-subrc IS INITIAL. 1714 | MOVE lv_xstring TO out. 1715 | ELSE. 1716 | MOVE in TO out. 1717 | ENDIF. 1718 | 1719 | ENDMETHOD. "string_to_xstring 1720 | 1721 | 1722 | METHOD TRIBOOL_TO_BOOL. 1723 | IF iv_tribool EQ c_tribool-true. 1724 | rv_bool = c_bool-true. 1725 | ELSEIF iv_tribool EQ c_tribool-undefined. 1726 | rv_bool = abap_undefined. " fall back to abap_undefined 1727 | ENDIF. 1728 | ENDMETHOD. "TRIBOOL_TO_BOOL 1729 | 1730 | 1731 | METHOD XSTRING_TO_STRING. 1732 | 1733 | DATA: lv_xstring TYPE xstring. 1734 | 1735 | " let us fix data conversion issues here 1736 | lv_xstring = in. 1737 | 1738 | CALL FUNCTION 'SSFC_BASE64_ENCODE' 1739 | EXPORTING 1740 | bindata = lv_xstring 1741 | IMPORTING 1742 | b64data = out 1743 | EXCEPTIONS 1744 | OTHERS = 1. 1745 | 1746 | IF sy-subrc IS NOT INITIAL. 1747 | MOVE in TO out. 1748 | ENDIF. 1749 | 1750 | ENDMETHOD. "xstring_to_string 1751 | ENDCLASS. 1752 | --------------------------------------------------------------------------------