├── 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://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 |