se24新建类ZCL_JSON保存
点击修改,进入下图界面,点击红框。
复制粘贴下面代码
CLASS zcl_json DEFINITIONPUBLICCREATE PUBLIC .PUBLIC SECTION.
*"* public components of class ZCL_JSON
*"* do not include other source files here!!!TYPE-POOLS abap .CLASS cl_abap_tstmp DEFINITION LOAD .CLASS cx_sy_conversion_error DEFINITION LOAD .TYPES json TYPE string .TYPES:BEGIN OF name_mapping,abap TYPE abap_compname,json TYPE string,END OF name_mapping .TYPES:name_mappings TYPE HASHED TABLE OF name_mapping WITH UNIQUE KEY abap .TYPES:ref_tab TYPE STANDARD TABLE OF REF TO data WITH DEFAULT KEY .TYPES bool TYPE char1 .TYPES tribool TYPE char1 .TYPES pretty_name_mode TYPE char1 .CONSTANTS:BEGIN OF pretty_mode,none TYPE char1 VALUE ``,low_case TYPE char1 VALUE `L`,camel_case TYPE char1 VALUE `X`,extended TYPE char1 VALUE `Y`,user TYPE char1 VALUE `U`,user_low_case TYPE char1 VALUE `C`,END OF pretty_mode .CONSTANTS:BEGIN OF c_bool,true TYPE bool VALUE `X`,false TYPE bool VALUE ``,END OF c_bool .CONSTANTS:BEGIN OF c_tribool,true TYPE tribool VALUE c_bool-true,false TYPE tribool VALUE `-`,undefined TYPE tribool VALUE ``,END OF c_tribool .CONSTANTS mc_key_separator TYPE string VALUE `-`. "#EC NOTEXTCONSTANTS version TYPE i VALUE 15. "#EC NOTEXTCLASS-DATA sv_white_space TYPE string READ-ONLY .CLASS-DATA mc_bool_types TYPE string READ-ONLY VALUE `\TYPE-POOL=ABAP\TYPE=ABAP_BOOL\TYPE=BOOLEAN\TYPE=BOOLE_D\TYPE=XFELD`. "#EC NOTEXT .CLASS-DATA mc_bool_3state TYPE string READ-ONLY VALUE `\TYPE=BOOLEAN`. "#EC NOTEXT .CLASS-DATA mc_json_type TYPE string READ-ONLY .CLASS-METHODS class_constructor .CLASS-METHODS string_to_xstringIMPORTING!in TYPE stringCHANGINGvalue(out) TYPE any .CLASS-METHODS xstring_to_stringIMPORTING!in TYPE anyRETURNINGvalue(out) TYPE string .CLASS-METHODS raw_to_stringIMPORTING!iv_xstring TYPE xstring!iv_encoding TYPE abap_encoding OPTIONALRETURNINGvalue(rv_string) TYPE string .CLASS-METHODS string_to_rawIMPORTING!iv_string TYPE string!iv_encoding TYPE abap_encoding OPTIONALRETURNINGvalue(rv_xstring) TYPE xstring .CLASS-METHODS deserializeIMPORTING!json TYPE json OPTIONAL!jsonx TYPE xstring OPTIONAL!pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none!assoc_arrays TYPE bool DEFAULT c_bool-false!assoc_arrays_opt TYPE bool DEFAULT c_bool-false!name_mappings TYPE name_mappings OPTIONAL!conversion_exits TYPE bool DEFAULT c_bool-falseCHANGING!data TYPE data .CLASS-METHODS serializeIMPORTING!data TYPE data!compress TYPE bool DEFAULT c_bool-false!name TYPE string OPTIONAL!pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none!type_descr TYPE REF TO cl_abap_typedescr OPTIONAL!assoc_arrays TYPE bool DEFAULT c_bool-false!ts_as_iso8601 TYPE bool DEFAULT c_bool-false!expand_includes TYPE bool DEFAULT c_bool-true!assoc_arrays_opt TYPE bool DEFAULT c_bool-false!numc_as_string TYPE bool DEFAULT c_bool-false!name_mappings TYPE name_mappings OPTIONAL!conversion_exits TYPE bool DEFAULT c_bool-falseRETURNINGvalue(r_json) TYPE json .METHODS deserialize_intIMPORTING!json TYPE json OPTIONAL!jsonx TYPE xstring OPTIONALCHANGING!data TYPE dataRAISINGcx_sy_move_cast_error .CLASS-METHODS generateIMPORTING!json TYPE json!pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none!name_mappings TYPE name_mappings OPTIONALRETURNINGvalue(rr_data) TYPE REF TO data .METHODS serialize_intIMPORTING!data TYPE data!name TYPE string OPTIONAL!type_descr TYPE REF TO cl_abap_typedescr OPTIONALRETURNINGvalue(r_json) TYPE json .METHODS generate_intIMPORTING!json TYPE jsonvalue(length) TYPE i OPTIONALRETURNINGvalue(rr_data) TYPE REF TO dataRAISINGcx_sy_move_cast_error .METHODS constructorIMPORTING!compress TYPE bool DEFAULT c_bool-false!pretty_name TYPE pretty_name_mode DEFAULT pretty_mode-none!assoc_arrays TYPE bool DEFAULT c_bool-false!ts_as_iso8601 TYPE bool DEFAULT c_bool-false!expand_includes TYPE bool DEFAULT c_bool-true!assoc_arrays_opt TYPE bool DEFAULT c_bool-false!strict_mode TYPE bool DEFAULT c_bool-false!numc_as_string TYPE bool DEFAULT c_bool-false!name_mappings TYPE name_mappings OPTIONAL!conversion_exits TYPE bool DEFAULT c_bool-false .CLASS-METHODS bool_to_triboolIMPORTING!iv_bool TYPE boolRETURNINGvalue(rv_tribool) TYPE tribool .CLASS-METHODS tribool_to_boolIMPORTING!iv_tribool TYPE triboolRETURNINGvalue(rv_bool) TYPE bool .PROTECTED SECTION.
*"* protected components of class ZCL_JSON
*"* do not include other source files here!!!TYPES:BEGIN OF t_s_symbol,header TYPE string,name TYPE string,type TYPE REF TO cl_abap_datadescr,value TYPE REF TO data,convexit_out TYPE string,convexit_in TYPE string,compressable TYPE abap_bool,read_only TYPE abap_bool,END OF t_s_symbol,t_t_symbol TYPE STANDARD TABLE OF t_s_symbol WITH DEFAULT KEY,BEGIN OF t_s_field_cache,name TYPE string,type TYPE REF TO cl_abap_datadescr,convexit_out TYPE string,convexit_in TYPE string,value TYPE REF TO data,END OF t_s_field_cache,t_t_field_cache TYPE HASHED TABLE OF t_s_field_cache WITH UNIQUE KEY name,name_mappings_ex TYPE HASHED TABLE OF name_mapping WITH UNIQUE KEY json.DATA mv_compress TYPE bool .DATA mv_pretty_name TYPE pretty_name_mode .DATA mv_assoc_arrays TYPE bool .DATA mv_ts_as_iso8601 TYPE bool .DATA mt_name_mappings TYPE name_mappings .DATA mt_name_mappings_ex TYPE name_mappings_ex .DATA mv_expand_includes TYPE bool .DATA mv_assoc_arrays_opt TYPE bool .DATA mv_strict_mode TYPE bool .DATA mv_numc_as_string TYPE bool .DATA mv_conversion_exits TYPE bool .CLASS-DATA mc_name_symbols_map TYPE string VALUE ` _/_\_:_;_~_._,_-_+_=_>_<_|_(_)_[_]_{_}_@_+_*_?_!_&_$_#_%_^_'_§_` ##no_text.CLASS-METHODS unescapeIMPORTINGescaped TYPE stringRETURNINGvalue(unescaped) TYPE string .CLASS-METHODS get_convexit_funcIMPORTINGelem_descr TYPE REF TO cl_abap_elemdescrinput TYPE abap_bool OPTIONALRETURNINGvalue(rv_func) TYPE string .METHODS dump_symbols FINALIMPORTINGit_symbols TYPE t_t_symbolRETURNINGvalue(r_json) TYPE json .METHODS get_symbols FINALIMPORTINGtype_descr TYPE REF TO cl_abap_typedescrdata TYPE REF TO data OPTIONALobject TYPE REF TO object OPTIONALinclude_aliases TYPE abap_bool DEFAULT abap_falseRETURNINGvalue(result) TYPE t_t_symbol .METHODS get_fields FINALIMPORTINGtype_descr TYPE REF TO cl_abap_typedescrdata TYPE REF TO data OPTIONALobject TYPE REF TO object OPTIONALRETURNINGvalue(rt_fields) TYPE t_t_field_cache .METHODS dump_intIMPORTINGdata TYPE datatype_descr TYPE REF TO cl_abap_typedescr OPTIONALconvexit TYPE string OPTIONALRETURNINGvalue(r_json) TYPE json .METHODS is_compressableIMPORTINGtype_descr TYPE REF TO cl_abap_typedescrname TYPE csequenceRETURNINGvalue(rv_compress) TYPE abap_bool .METHODS restoreIMPORTINGjson TYPE jsonlength TYPE ivalue(type_descr) TYPE REF TO cl_abap_typedescr OPTIONALfield_cache TYPE t_t_field_cache OPTIONALCHANGINGdata TYPE data OPTIONALoffset TYPE i DEFAULT 0RAISINGcx_sy_move_cast_error .METHODS restore_typeIMPORTINGjson TYPE jsonlength TYPE ivalue(type_descr) TYPE REF TO cl_abap_typedescr OPTIONALfield_cache TYPE t_t_field_cache OPTIONALconvexit TYPE string OPTIONALCHANGINGdata TYPE data OPTIONALoffset TYPE i DEFAULT 0RAISINGcx_sy_move_cast_error .METHODS dump_typeIMPORTINGdata TYPE datatype_descr TYPE REF TO cl_abap_elemdescrconvexit TYPE stringRETURNINGvalue(r_json) TYPE json .METHODS pretty_name_exIMPORTINGin TYPE csequenceRETURNINGvalue(out) TYPE string .METHODS generate_int_ex FINALIMPORTINGjson TYPE jsonlength TYPE iCHANGINGdata TYPE dataoffset TYPE i .METHODS pretty_nameIMPORTINGin TYPE csequenceRETURNINGvalue(out) TYPE string .CLASS-METHODS escapeIMPORTINGin TYPE anyRETURNINGvalue(out) TYPE string .CLASS-METHODS edm_datetime_to_tsIMPORTINGticks TYPE stringoffset TYPE string OPTIONALtypekind TYPE abap_typekindRETURNINGvalue(r_data) TYPE string .PRIVATE SECTION.
*"* private components of class ZCL_JSON
*"* do not include other source files here!!!DATA mv_extended TYPE bool .CLASS-DATA mc_me_type TYPE string .CLASS-DATA mc_cov_error TYPE c .
ENDCLASS.CLASS ZCL_JSON IMPLEMENTATION.* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>BOOL_TO_TRIBOOL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_BOOL TYPE BOOL
* | [<-()] RV_TRIBOOL TYPE TRIBOOL
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD bool_to_tribool.IF iv_bool EQ c_bool-true.rv_tribool = c_tribool-true.ELSEIF iv_bool EQ abap_undefined. " fall back for abap _boolrv_tribool = c_tribool-undefined.ELSE.rv_tribool = c_tribool-false.ENDIF.ENDMETHOD. "BOOL_TO_TRIBOOL* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>CLASS_CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD class_constructor.DATA: lo_bool_type_descr TYPE REF TO cl_abap_typedescr,lo_tribool_type_descr TYPE REF TO cl_abap_typedescr,lo_json_type_descr TYPE REF TO cl_abap_typedescr,lv_pos LIKE sy-fdpos,lv_json_string TYPE json.lo_bool_type_descr = cl_abap_typedescr=>describe_by_data( c_bool-true ).lo_tribool_type_descr = cl_abap_typedescr=>describe_by_data( c_tribool-true ).lo_json_type_descr = cl_abap_typedescr=>describe_by_data( lv_json_string ).CONCATENATE mc_bool_types lo_bool_type_descr->absolute_name lo_tribool_type_descr->absolute_name INTO mc_bool_types.CONCATENATE mc_bool_3state lo_tribool_type_descr->absolute_name INTO mc_bool_3state.CONCATENATE mc_json_type lo_json_type_descr->absolute_name INTO mc_json_type.FIND FIRST OCCURRENCE OF `\TYPE=` IN lo_json_type_descr->absolute_name MATCH OFFSET lv_pos.IF sy-subrc IS INITIAL.mc_me_type = lo_json_type_descr->absolute_name(lv_pos).ENDIF.sv_white_space = cl_abap_char_utilities=>get_simple_spaces_for_cur_cp( ).mc_cov_error = cl_abap_conv_in_ce=>uccp( '0000' ).ENDMETHOD. "CLASS_CONSTRUCTOR* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_JSON->CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* | [--->] COMPRESS TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] PRETTY_NAME TYPE PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [--->] ASSOC_ARRAYS TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] TS_AS_ISO8601 TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] EXPAND_INCLUDES TYPE BOOL (default =C_BOOL-TRUE)
* | [--->] ASSOC_ARRAYS_OPT TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] STRICT_MODE TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] NUMC_AS_STRING TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] NAME_MAPPINGS TYPE NAME_MAPPINGS(optional)
* | [--->] CONVERSION_EXITS TYPE BOOL (default =C_BOOL-FALSE)
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD constructor.DATA: rtti TYPE REF TO cl_abap_classdescr,pair LIKE LINE OF name_mappings.mv_compress = compress.mv_pretty_name = pretty_name.mv_assoc_arrays = assoc_arrays.mv_ts_as_iso8601 = ts_as_iso8601.mv_expand_includes = expand_includes.mv_assoc_arrays_opt = assoc_arrays_opt.mv_strict_mode = strict_mode.mv_numc_as_string = numc_as_string.mv_conversion_exits = conversion_exits.LOOP AT name_mappings INTO pair.TRANSLATE pair-abap TO UPPER CASE.INSERT pair INTO TABLE mt_name_mappings.ENDLOOP." if it dumps here, you have passed ambiguous mapping to the API" please check your code for duplicates, pairs ABAP - JSON shall be uniqueINSERT LINES OF mt_name_mappings INTO TABLE mt_name_mappings_ex.IF mt_name_mappings IS NOT INITIAL.IF mv_pretty_name EQ pretty_mode-none.mv_pretty_name = pretty_mode-user.ELSEIF pretty_name EQ pretty_mode-low_case.mv_pretty_name = pretty_mode-user_low_case.ENDIF.ENDIF.rtti ?= cl_abap_classdescr=>describe_by_object_ref( me ).IF rtti->absolute_name NE mc_me_type.mv_extended = c_bool-true.ENDIF.ENDMETHOD. "CONSTRUCTOR* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>DESERIALIZE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON TYPE JSON(optional)
* | [--->] JSONX TYPE XSTRING(optional)
* | [--->] PRETTY_NAME TYPE PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [--->] ASSOC_ARRAYS TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] ASSOC_ARRAYS_OPT TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] NAME_MAPPINGS TYPE NAME_MAPPINGS(optional)
* | [--->] CONVERSION_EXITS TYPE BOOL (default =C_BOOL-FALSE)
* | [<-->] DATA TYPE DATA
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD deserialize.DATA: lo_json TYPE REF TO zcl_json." **********************************************************************" Usage examples and documentation can be found on SCN:" http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer" ********************************************************************** "IF json IS NOT INITIAL OR jsonx IS NOT INITIAL.CREATE OBJECT lo_jsonEXPORTINGpretty_name = pretty_namename_mappings = name_mappingsassoc_arrays = assoc_arraysconversion_exits = conversion_exitsassoc_arrays_opt = assoc_arrays_opt.TRY .lo_json->deserialize_int( EXPORTING json = json jsonx = jsonx CHANGING data = data ).CATCH cx_sy_move_cast_error. "#EC NO_HANDLERENDTRY.ENDIF.ENDMETHOD. "DESERIALIZE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_JSON->DESERIALIZE_INT
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON TYPE JSON(optional)
* | [--->] JSONX TYPE XSTRING(optional)
* | [<-->] DATA TYPE DATA
* | [!CX!] CX_SY_MOVE_CAST_ERROR
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD deserialize_int.DATA: length TYPE i,offset TYPE i,unescaped LIKE json." **********************************************************************" Usage examples and documentation can be found on SCN:" http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer" ********************************************************************** "IF json IS NOT INITIAL OR jsonx IS NOT INITIAL.IF jsonx IS NOT INITIAL.unescaped = raw_to_string( jsonx ).ELSE.unescaped = json.ENDIF." skip leading BOM signslength = strlen( unescaped ).while_offset_not_cs `"{[` unescaped.unescaped = unescaped+offset.length = length - offset.restore_type( EXPORTING json = unescaped length = length CHANGING data = data ).ENDIF.ENDMETHOD. "DESERIALIZE_INT* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->DUMP_INT
* +-------------------------------------------------------------------------------------------------+
* | [--->] DATA TYPE DATA
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR(optional)
* | [--->] CONVEXIT TYPE STRING(optional)
* | [<-()] R_JSON TYPE JSON
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD dump_int.DATA: lo_typedesc TYPE REF TO cl_abap_typedescr,lo_elem_descr TYPE REF TO cl_abap_elemdescr,lo_classdesc TYPE REF TO cl_abap_classdescr,lo_structdesc TYPE REF TO cl_abap_structdescr,lo_tabledescr TYPE REF TO cl_abap_tabledescr,lt_symbols TYPE t_t_symbol,lt_keys LIKE lt_symbols,lt_properties TYPE STANDARD TABLE OF string,lt_fields TYPE STANDARD TABLE OF string,lo_obj_ref TYPE REF TO object,lo_data_ref TYPE REF TO data,ls_skip_key TYPE LINE OF abap_keydescr_tab,lv_array_opt TYPE abap_bool,lv_prop_name TYPE string,lv_keyval TYPE string,lv_itemval TYPE string.FIELD-SYMBOLS: <line> TYPE any,<value> TYPE any,<data> TYPE data,<key> TYPE LINE OF abap_keydescr_tab,<symbol> LIKE LINE OF lt_symbols,<table> TYPE ANY TABLE." we need here macro instead of method calls because of the performance reasons." based on SAT measurements.CASE type_descr->kind.WHEN cl_abap_typedescr=>kind_ref.IF data IS INITIAL.r_json = `null`. "#EC NOTEXTELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref.lo_data_ref ?= data.lo_typedesc = cl_abap_typedescr=>describe_by_data_ref( lo_data_ref ).ASSIGN lo_data_ref->* TO <data>.r_json = dump_int( data = <data> type_descr = lo_typedesc ).ELSE.lo_obj_ref ?= data.lo_classdesc ?= cl_abap_typedescr=>describe_by_object_ref( lo_obj_ref ).lt_symbols = get_symbols( type_descr = lo_classdesc object = lo_obj_ref ).r_json = dump_symbols( lt_symbols ).ENDIF.WHEN cl_abap_typedescr=>kind_elem.lo_elem_descr ?= type_descr.dump_type data lo_elem_descr r_json convexit.WHEN cl_abap_typedescr=>kind_struct.lo_structdesc ?= type_descr.GET REFERENCE OF data INTO lo_data_ref.lt_symbols = get_symbols( type_descr = lo_structdesc data = lo_data_ref ).r_json = dump_symbols( lt_symbols ).WHEN cl_abap_typedescr=>kind_table.lo_tabledescr ?= type_descr.lo_typedesc = lo_tabledescr->get_table_line_type( ).ASSIGN data TO <table>." optimization for structured tablesIF lo_typedesc->kind EQ cl_abap_typedescr=>kind_struct.lo_structdesc ?= lo_typedesc.CREATE DATA lo_data_ref LIKE LINE OF <table>.ASSIGN lo_data_ref->* TO <line>.lt_symbols = get_symbols( type_descr = lo_structdesc data = lo_data_ref )." here we have differentiation of output of simple table to JSON array" and sorted or hashed table with unique key into JSON associative arrayIF lo_tabledescr->has_unique_key IS NOT INITIAL AND mv_assoc_arrays IS NOT INITIAL.IF lo_tabledescr->key_defkind EQ lo_tabledescr->keydefkind_user.LOOP AT lo_tabledescr->key ASSIGNING <key>.READ TABLE lt_symbols WITH KEY name = <key>-name ASSIGNING <symbol>.APPEND <symbol> TO lt_keys.ENDLOOP.ENDIF.IF lines( lo_tabledescr->key ) EQ 1.READ TABLE lo_tabledescr->key INDEX 1 INTO ls_skip_key.DELETE lt_symbols WHERE name EQ ls_skip_key-name." remove object wrapping for simple name-value tablesIF mv_assoc_arrays_opt EQ abap_true AND lines( lt_symbols ) EQ 1.lv_array_opt = abap_true.ENDIF.ENDIF.LOOP AT <table> INTO <line>.CLEAR: lt_fields, lv_prop_name.LOOP AT lt_symbols ASSIGNING <symbol>.ASSIGN <symbol>-value->* TO <value>.IF mv_compress IS INITIAL OR <value> IS NOT INITIAL OR <symbol>-compressable EQ abap_false.IF <symbol>-type->kind EQ cl_abap_typedescr=>kind_elem.lo_elem_descr ?= <symbol>-type.dump_type <value> lo_elem_descr lv_itemval <symbol>-convexit_out.ELSE.lv_itemval = dump_int( data = <value> type_descr = <symbol>-type convexit = <symbol>-convexit_out ).ENDIF.IF lv_array_opt EQ abap_false.CONCATENATE <symbol>-header lv_itemval INTO lv_itemval.ENDIF.APPEND lv_itemval TO lt_fields.ENDIF.ENDLOOP.IF lo_tabledescr->key_defkind EQ lo_tabledescr->keydefkind_user.LOOP AT lt_keys ASSIGNING <symbol>.ASSIGN <symbol>-value->* TO <value>.lv_keyval = <value>.CONDENSE lv_keyval.IF lv_prop_name IS NOT INITIAL.CONCATENATE lv_prop_name mc_key_separator lv_keyval INTO lv_prop_name.ELSE.lv_prop_name = lv_keyval.ENDIF.ENDLOOP.ELSE.LOOP AT lt_symbols ASSIGNING <symbol>.ASSIGN <symbol>-value->* TO <value>.lv_keyval = <value>.CONDENSE lv_keyval.IF lv_prop_name IS NOT INITIAL.CONCATENATE lv_prop_name mc_key_separator lv_keyval INTO lv_prop_name.ELSE.lv_prop_name = lv_keyval.ENDIF.ENDLOOP.ENDIF.CONCATENATE LINES OF lt_fields INTO lv_itemval SEPARATED BY `,`.IF lv_array_opt EQ abap_false.CONCATENATE `"` lv_prop_name `":{` lv_itemval `}` INTO lv_itemval.ELSE.CONCATENATE `"` lv_prop_name `":` lv_itemval `` INTO lv_itemval.ENDIF.APPEND lv_itemval TO lt_properties.ENDLOOP.CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`.CONCATENATE `{` r_json `}` INTO r_json.ELSE.LOOP AT <table> INTO <line>.CLEAR lt_fields.LOOP AT lt_symbols ASSIGNING <symbol>.ASSIGN <symbol>-value->* TO <value>.IF mv_compress IS INITIAL OR <value> IS NOT INITIAL OR <symbol>-compressable EQ abap_false.IF <symbol>-type->kind EQ cl_abap_typedescr=>kind_elem.lo_elem_descr ?= <symbol>-type.dump_type <value> lo_elem_descr lv_itemval <symbol>-convexit_out.ELSE.lv_itemval = dump_int( data = <value> type_descr = <symbol>-type convexit = <symbol>-convexit_out ).ENDIF.CONCATENATE <symbol>-header lv_itemval INTO lv_itemval.APPEND lv_itemval TO lt_fields.ENDIF.ENDLOOP.CONCATENATE LINES OF lt_fields INTO lv_itemval SEPARATED BY `,`.CONCATENATE `{` lv_itemval `}` INTO lv_itemval.APPEND lv_itemval TO lt_properties.ENDLOOP.CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`.CONCATENATE `[` r_json `]` INTO r_json.ENDIF.ELSE.LOOP AT <table> ASSIGNING <value>.lv_itemval = dump_int( data = <value> type_descr = lo_typedesc ).APPEND lv_itemval TO lt_properties.ENDLOOP.CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`.CONCATENATE `[` r_json `]` INTO r_json.ENDIF.ENDCASE.ENDMETHOD. "DUMP_INT* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->DUMP_SYMBOLS
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_SYMBOLS TYPE T_T_SYMBOL
* | [<-()] R_JSON TYPE JSON
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD dump_symbols.DATA: lv_properties TYPE STANDARD TABLE OF string,lv_itemval TYPE string.FIELD-SYMBOLS: <value> TYPE any,<symbol> LIKE LINE OF it_symbols.LOOP AT it_symbols ASSIGNING <symbol>.ASSIGN <symbol>-value->* TO <value>.IF mv_compress IS INITIAL OR <value> IS NOT INITIAL OR <symbol>-compressable EQ abap_false.lv_itemval = dump_int( data = <value> type_descr = <symbol>-type convexit = <symbol>-convexit_out ).CONCATENATE <symbol>-header lv_itemval INTO lv_itemval.APPEND lv_itemval TO lv_properties.ENDIF.ENDLOOP.CONCATENATE LINES OF lv_properties INTO r_json SEPARATED BY `,`.CONCATENATE `{` r_json `}` INTO r_json.ENDMETHOD. "DUMP_SYMBOLS* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->DUMP_TYPE
* +-------------------------------------------------------------------------------------------------+
* | [--->] DATA TYPE DATA
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_ELEMDESCR
* | [--->] CONVEXIT TYPE STRING
* | [<-()] R_JSON TYPE JSON
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD dump_type.CONSTANTS: lc_typekind_utclong TYPE abap_typekind VALUE 'p', " CL_ABAP_TYPEDESCR=>TYPEKIND_UTCLONG -> 'p' only from 7.60lc_typekind_int8 TYPE abap_typekind VALUE '8'. " TYPEKIND_INT8 -> '8' only from 7.40IF convexit IS NOT INITIAL AND data IS NOT INITIAL.TRY.CALL FUNCTION convexitEXPORTINGinput = dataIMPORTINGoutput = r_jsonEXCEPTIONSOTHERS = 1.IF sy-subrc IS INITIAL.CONCATENATE `"` r_json `"` INTO r_json.ENDIF.CATCH cx_root. "#EC NO_HANDLERENDTRY.ELSE.CASE type_descr->type_kind.WHEN cl_abap_typedescr=>typekind_float OR cl_abap_typedescr=>typekind_int OR cl_abap_typedescr=>typekind_int1 ORcl_abap_typedescr=>typekind_int2 OR cl_abap_typedescr=>typekind_packed OR lc_typekind_utclong OR lc_typekind_int8.IF mv_ts_as_iso8601 EQ c_bool-true AND( type_descr->type_kind EQ lc_typekind_utclong OR( type_descr->type_kind EQ cl_abap_typedescr=>typekind_packed AND type_descr->absolute_name CP `\TYPE=TIMESTAMP*` ) ).IF data IS INITIAL.r_json = `""`.ELSE.r_json = data.IF type_descr->absolute_name EQ `\TYPE=TIMESTAMP`.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.ELSEIF type_descr->absolute_name EQ `\TYPE=TIMESTAMPL`.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.ENDIF.ENDIF.ELSEIF data IS INITIAL.r_json = `0`.ELSE.r_json = data.IF data LT 0.IF type_descr->type_kind <> cl_abap_typedescr=>typekind_float. "float: sign is already at the beginningSHIFT r_json RIGHT CIRCULAR.ENDIF.ELSE.CONDENSE r_json.ENDIF.ENDIF.WHEN cl_abap_typedescr=>typekind_num.IF mv_numc_as_string EQ abap_true.IF data IS INITIAL.r_json = `""`.ELSE.CONCATENATE `"` data `"` INTO r_json.ENDIF.ELSE.r_json = data.SHIFT r_json LEFT DELETING LEADING ` 0`.IF r_json IS INITIAL.r_json = `0`.ENDIF.ENDIF.WHEN cl_abap_typedescr=>typekind_string OR cl_abap_typedescr=>typekind_csequence OR cl_abap_typedescr=>typekind_clike.IF data IS INITIAL.r_json = `""`.ELSEIF type_descr->absolute_name EQ mc_json_type.r_json = data.ELSE.r_json = escape( data ).CONCATENATE `"` r_json `"` INTO r_json.ENDIF.WHEN cl_abap_typedescr=>typekind_xstring OR cl_abap_typedescr=>typekind_hex.IF data IS INITIAL.r_json = `""`.ELSE.r_json = xstring_to_string( data ).r_json = escape( r_json ).CONCATENATE `"` r_json `"` INTO r_json.ENDIF.WHEN cl_abap_typedescr=>typekind_char.IF type_descr->output_length EQ 1 AND mc_bool_types CS type_descr->absolute_name.IF data EQ c_bool-true.r_json = `true`. "#EC NOTEXTELSEIF mc_bool_3state CS type_descr->absolute_name AND data IS INITIAL.r_json = `null`. "#EC NOTEXTELSE.r_json = `false`. "#EC NOTEXTENDIF.ELSE.r_json = escape( data ).CONCATENATE `"` r_json `"` INTO r_json.ENDIF.WHEN cl_abap_typedescr=>typekind_date.CONCATENATE `"` data(4) `-` data+4(2) `-` data+6(2) `"` INTO r_json.WHEN cl_abap_typedescr=>typekind_time.CONCATENATE `"` data(2) `:` data+2(2) `:` data+4(2) `"` INTO r_json.WHEN 'k'. " cl_abap_typedescr=>typekind_enumr_json = data.CONCATENATE `"` r_json `"` INTO r_json.WHEN OTHERS.IF data IS INITIAL.r_json = `null`. "#EC NOTEXTELSE.r_json = data.ENDIF.ENDCASE.ENDIF.ENDMETHOD. "DUMP_TYPE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Protected Method ZCL_JSON=>EDM_DATETIME_TO_TS
* +-------------------------------------------------------------------------------------------------+
* | [--->] TICKS TYPE STRING
* | [--->] OFFSET TYPE STRING(optional)
* | [--->] TYPEKIND TYPE ABAP_TYPEKIND
* | [<-()] R_DATA TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD edm_datetime_to_ts.CONSTANTS: lc_epochs TYPE string VALUE `19700101000000`.DATA: lv_ticks TYPE p,lv_seconds TYPE p,lv_subsec TYPE p,lv_timestamps TYPE string,lv_timestamp TYPE timestampl VALUE `19700101000000.0000000`.lv_ticks = ticks.lv_seconds = lv_ticks / 1000. " in secondslv_subsec = lv_ticks MOD 1000. " in subsecIF lv_subsec GT 0.lv_timestamps = lv_subsec.CONCATENATE lc_epochs `.` lv_timestamps INTO lv_timestamps.lv_timestamp = lv_timestamps.ENDIF.lv_timestamp = cl_abap_tstmp=>add( tstmp = lv_timestamp secs = lv_seconds ).IF offset IS NOT INITIAL.lv_ticks = offset+1.lv_ticks = lv_ticks * 60. "offset is in minutesIF offset(1) = '+'.lv_timestamp = cl_abap_tstmp=>subtractsecs( tstmp = lv_timestamp secs = lv_ticks ).ELSE.lv_timestamp = cl_abap_tstmp=>add( tstmp = lv_timestamp secs = lv_ticks ).ENDIF.ENDIF.CASE typekind.WHEN cl_abap_typedescr=>typekind_time.r_data = lv_timestamp.r_data = r_data+8(6).WHEN cl_abap_typedescr=>typekind_date.r_data = lv_timestamp.r_data = r_data(8).WHEN cl_abap_typedescr=>typekind_packed.r_data = lv_timestamp.ENDCASE.ENDMETHOD. "EDM_DATETIME_TO_TS* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Protected Method ZCL_JSON=>ESCAPE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IN TYPE ANY
* | [<-()] OUT TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD escape.out = in.REPLACE ALL OCCURRENCES OF `\` IN out WITH `\\`.REPLACE ALL OCCURRENCES OF `"` IN out WITH `\"`.ENDMETHOD. "ESCAPE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>GENERATE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON TYPE JSON
* | [--->] PRETTY_NAME TYPE PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [--->] NAME_MAPPINGS TYPE NAME_MAPPINGS(optional)
* | [<-()] RR_DATA TYPE REF TO DATA
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD generate.DATA: lo_json TYPE REF TO zcl_json,offset TYPE i,length TYPE i,lv_json LIKE json." skip leading BOM signslength = strlen( json ).while_offset_not_cs `"{[` json.lv_json = json+offset.length = length - offset.CREATE OBJECT lo_jsonEXPORTINGpretty_name = pretty_namename_mappings = name_mappingsassoc_arrays = c_bool-trueassoc_arrays_opt = c_bool-true.TRY .rr_data = lo_json->generate_int( json = lv_json length = length ).CATCH cx_sy_move_cast_error. "#EC NO_HANDLERENDTRY.ENDMETHOD. "GENERATE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_JSON->GENERATE_INT
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON TYPE JSON
* | [--->] LENGTH TYPE I(optional)
* | [<-()] RR_DATA TYPE REF TO DATA
* | [!CX!] CX_SY_MOVE_CAST_ERROR
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD generate_int.TYPES: BEGIN OF ts_field,name TYPE string,value TYPE json,END OF ts_field.DATA: offset TYPE i.DATA: lt_json TYPE STANDARD TABLE OF json WITH DEFAULT KEY,lv_comp_name TYPE abap_compname,lt_fields TYPE SORTED TABLE OF ts_field WITH UNIQUE KEY name,lo_type TYPE REF TO cl_abap_datadescr,lt_comp TYPE abap_component_tab,lt_names TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line,cache LIKE LINE OF mt_name_mappings_ex,ls_comp LIKE LINE OF lt_comp.FIELD-SYMBOLS: <data> TYPE any,<struct> TYPE any,<json> LIKE LINE OF lt_json,<field> LIKE LINE OF lt_fields,<table> TYPE STANDARD TABLE,<cache> LIKE LINE OF mt_name_mappings_ex.IF length IS NOT SUPPLIED.length = strlen( json ).ENDIF.eat_white.CASE json+offset(1).WHEN `{`."result must be a structurerestore_type( EXPORTING json = json length = length CHANGING data = lt_fields ).IF lt_fields IS NOT INITIAL.ls_comp-type = cl_abap_refdescr=>get_ref_to_data( ).LOOP AT lt_fields ASSIGNING <field>.READ TABLE mt_name_mappings_ex WITH TABLE KEY json = <field>-name ASSIGNING <cache>.IF sy-subrc IS INITIAL.ls_comp-name = <cache>-abap.ELSE.cache-json = ls_comp-name = <field>-name." remove characters not allowed in component namesTRANSLATE ls_comp-name USING ` _/_\_:_~_._-_=_>_<_(_)_@_+_*_?_&_$_#_%_^_`.IF mv_pretty_name EQ pretty_mode-camel_case OR mv_pretty_name EQ pretty_mode-extended.REPLACE ALL OCCURRENCES OF REGEX `([a-z])([A-Z])` IN ls_comp-name WITH `$1_$2`. "#EC NOTEXTENDIF.TRANSLATE ls_comp-name TO UPPER CASE.cache-abap = ls_comp-name = lv_comp_name = ls_comp-name. " truncate by allowed field name lengthINSERT cache INTO TABLE mt_name_mappings_ex.ENDIF.INSERT ls_comp-name INTO TABLE lt_names.IF sy-subrc IS INITIAL.APPEND ls_comp TO lt_comp.ELSE.DELETE lt_fields.ENDIF.ENDLOOP.TRY.lo_type = cl_abap_structdescr=>create( p_components = lt_comp p_strict = c_bool-false ).CREATE DATA rr_data TYPE HANDLE lo_type.ASSIGN rr_data->* TO <struct>.LOOP AT lt_fields ASSIGNING <field>.ASSIGN COMPONENT sy-tabix OF STRUCTURE <struct> TO <data>.<data> = generate_int( <field>-value ).ENDLOOP.CATCH cx_sy_create_data_error cx_sy_struct_creation. "#EC NO_HANDLERENDTRY.ENDIF.RETURN.WHEN `[`."result must be a table of refrestore_type( EXPORTING json = json length = length CHANGING data = lt_json ).CREATE DATA rr_data TYPE TABLE OF REF TO data.ASSIGN rr_data->* TO <table>.LOOP AT lt_json ASSIGNING <json>.APPEND INITIAL LINE TO <table> ASSIGNING <data>.<data> = generate_int( <json> ).ENDLOOP.RETURN.WHEN `"`."stringCREATE DATA rr_data TYPE string.WHEN `-` OR `0` OR `1` OR `2` OR `3` OR `4` OR `5` OR `6` OR `7` OR `8` OR `9`. " numberIF json+offset CS '.'.CREATE DATA rr_data TYPE f.ELSEIF length GT 9.CREATE DATA rr_data TYPE p.ELSE.CREATE DATA rr_data TYPE i.ENDIF.WHEN OTHERS.IF json+offset EQ `true` OR json+offset EQ `false`. "#EC NOTEXTCREATE DATA rr_data TYPE abap_bool.ENDIF.ENDCASE.IF rr_data IS BOUND.ASSIGN rr_data->* TO <data>.restore_type( EXPORTING json = json length = length CHANGING data = <data> ).ENDIF.ENDMETHOD. "GENERATE_INT* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->GENERATE_INT_EX
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON TYPE JSON
* | [--->] LENGTH TYPE I
* | [<-->] DATA TYPE DATA
* | [<-->] OFFSET TYPE I
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD generate_int_ex.DATA: lv_assoc_arrays LIKE mv_assoc_arrays,lv_assoc_arrays_opt LIKE mv_assoc_arrays_opt,lv_mark LIKE offset,lv_match LIKE lv_mark,lv_json TYPE zcl_json=>json.lv_mark = offset.restore_type( EXPORTING json = json length = length CHANGING offset = offset ).lv_match = offset - lv_mark.lv_json = json+lv_mark(lv_match).lv_assoc_arrays = mv_assoc_arrays.lv_assoc_arrays_opt = mv_assoc_arrays_opt.mv_assoc_arrays = abap_true.mv_assoc_arrays_opt = abap_true.data = generate_int( lv_json ).mv_assoc_arrays = lv_assoc_arrays.mv_assoc_arrays_opt = lv_assoc_arrays_opt.ENDMETHOD. "GENERATE_INT_EX* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Protected Method ZCL_JSON=>GET_CONVEXIT_FUNC
* +-------------------------------------------------------------------------------------------------+
* | [--->] ELEM_DESCR TYPE REF TO CL_ABAP_ELEMDESCR
* | [--->] INPUT TYPE ABAP_BOOL(optional)
* | [<-()] RV_FUNC TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD get_convexit_func.DATA: ls_dfies TYPE dfies.elem_descr->get_ddic_field(RECEIVINGp_flddescr = ls_dfies " Field DescriptionEXCEPTIONSnot_found = 1no_ddic_type = 2OTHERS = 3).IF sy-subrc IS INITIAL AND ls_dfies-convexit IS NOT INITIAL.IF input EQ abap_true.CONCATENATE 'CONVERSION_EXIT_' ls_dfies-convexit '_INPUT' INTO rv_func.ELSE.CONCATENATE 'CONVERSION_EXIT_' ls_dfies-convexit '_OUTPUT' INTO rv_func.ENDIF.ENDIF.ENDMETHOD. "GET_CONVEXIT_FUNC* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->GET_FIELDS
* +-------------------------------------------------------------------------------------------------+
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR
* | [--->] DATA TYPE REF TO DATA(optional)
* | [--->] OBJECT TYPE REF TO OBJECT(optional)
* | [<-()] RT_FIELDS TYPE T_T_FIELD_CACHE
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD get_fields.DATA: lt_symbols TYPE t_t_symbol,lv_name TYPE char128,ls_field LIKE LINE OF rt_fields.FIELD-SYMBOLS: <sym> LIKE LINE OF lt_symbols,<cache> LIKE LINE OF mt_name_mappings.lt_symbols = get_symbols( type_descr = type_descr data = data object = object include_aliases = abap_true ).LOOP AT lt_symbols ASSIGNING <sym> WHERE read_only EQ abap_false.MOVE-CORRESPONDING <sym> TO ls_field." insert as UPPER CASEINSERT ls_field INTO TABLE rt_fields." insert as lower case
* TRANSLATE ls_field-name TO LOWER CASE.
* INSERT ls_field INTO TABLE rt_fields." as pretty printedIF mv_pretty_name NE pretty_mode-none AND mv_pretty_name NE pretty_mode-low_case.format_name <sym>-name mv_pretty_name ls_field-name.INSERT ls_field INTO TABLE rt_fields." let us check for not well formed canelCase to be compatible with old logiclv_name = ls_field-name.TRANSLATE lv_name(1) TO UPPER CASE.ls_field-name = lv_name.INSERT ls_field INTO TABLE rt_fields.ENDIF.ENDLOOP.ENDMETHOD. "GET_FIELDS* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->GET_SYMBOLS
* +-------------------------------------------------------------------------------------------------+
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR
* | [--->] DATA TYPE REF TO DATA(optional)
* | [--->] OBJECT TYPE REF TO OBJECT(optional)
* | [--->] INCLUDE_ALIASES TYPE ABAP_BOOL (default =ABAP_FALSE)
* | [<-()] RESULT TYPE T_T_SYMBOL
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD get_symbols.DATA: comp_tab TYPE cl_abap_structdescr=>component_table,symb_tab LIKE result,symb LIKE LINE OF symb_tab,elem_descr TYPE REF TO cl_abap_elemdescr,class_descr TYPE REF TO cl_abap_classdescr,struct_descr TYPE REF TO cl_abap_structdescr.FIELD-SYMBOLS: <comp> LIKE LINE OF comp_tab,<attr> LIKE LINE OF cl_abap_objectdescr=>attributes,<cache> LIKE LINE OF mt_name_mappings,<field> TYPE any.IF type_descr->kind EQ cl_abap_typedescr=>kind_struct.struct_descr ?= type_descr.comp_tab = struct_descr->get_components( ).LOOP AT comp_tab ASSIGNING <comp>.IF <comp>-name IS NOT INITIAL AND( <comp>-as_include EQ abap_false OR include_aliases EQ abap_true OR mv_expand_includes EQ abap_false ).symb-name = <comp>-name.symb-type = <comp>-type.IF data IS BOUND.IF mv_conversion_exits EQ abap_true AND symb-type->kind EQ cl_abap_typedescr=>kind_elem.elem_descr ?= symb-type.symb-convexit_in = get_convexit_func( elem_descr = elem_descr input = abap_true ).symb-convexit_out = get_convexit_func( elem_descr = elem_descr input = abap_false ).ENDIF.is_compressable symb-type symb-name symb-compressable.ASSIGN data->(symb-name) TO <field>.GET REFERENCE OF <field> INTO symb-value.format_name symb-name mv_pretty_name symb-header.CONCATENATE `"` symb-header `":` INTO symb-header.ENDIF.APPEND symb TO result.ENDIF.IF <comp>-as_include EQ abap_true AND mv_expand_includes EQ abap_true.struct_descr ?= <comp>-type.symb_tab = get_symbols( type_descr = struct_descr include_aliases = include_aliases ).LOOP AT symb_tab INTO symb.CONCATENATE symb-name <comp>-suffix INTO symb-name.IF data IS BOUND.IF mv_conversion_exits EQ abap_true AND symb-type->kind EQ cl_abap_typedescr=>kind_elem.elem_descr ?= symb-type.symb-convexit_in = get_convexit_func( elem_descr = elem_descr input = abap_true ).symb-convexit_out = get_convexit_func( elem_descr = elem_descr input = abap_false ).ENDIF.is_compressable symb-type symb-name symb-compressable.ASSIGN data->(symb-name) TO <field>.GET REFERENCE OF <field> INTO symb-value.format_name symb-name mv_pretty_name symb-header.CONCATENATE `"` symb-header `":` INTO symb-header.ENDIF.APPEND symb TO result.ENDLOOP.ENDIF.ENDLOOP.ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_class.class_descr ?= type_descr.LOOP AT class_descr->attributes ASSIGNING <attr> WHERE is_constant IS INITIAL AND alias_for IS INITIAL AND( is_interface IS INITIAL OR type_kind NE cl_abap_typedescr=>typekind_oref ).ASSIGN object->(<attr>-name) TO <field>.CHECK sy-subrc IS INITIAL. " we can only assign to public attributessymb-name = <attr>-name.symb-read_only = <attr>-is_read_only.symb-type = class_descr->get_attribute_type( <attr>-name ).IF mv_conversion_exits EQ abap_true AND symb-type->kind EQ cl_abap_typedescr=>kind_elem.elem_descr ?= symb-type.symb-convexit_in = get_convexit_func( elem_descr = elem_descr input = abap_true ).symb-convexit_out = get_convexit_func( elem_descr = elem_descr input = abap_false ).ENDIF.is_compressable symb-type symb-name symb-compressable.GET REFERENCE OF <field> INTO symb-value.format_name symb-name mv_pretty_name symb-header.CONCATENATE `"` symb-header `":` INTO symb-header.APPEND symb TO result.ENDLOOP.ENDIF.ENDMETHOD. "GET_SYMBOLS* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->IS_COMPRESSABLE
* +-------------------------------------------------------------------------------------------------+
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR
* | [--->] NAME TYPE CSEQUENCE
* | [<-()] RV_COMPRESS TYPE ABAP_BOOL
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD is_compressable.rv_compress = abap_true.ENDMETHOD. "IS_COMPRESSABLE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->PRETTY_NAME
* +-------------------------------------------------------------------------------------------------+
* | [--->] IN TYPE CSEQUENCE
* | [<-()] OUT TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD pretty_name.DATA: tokens TYPE TABLE OF char128,cache LIKE LINE OF mt_name_mappings.FIELD-SYMBOLS: <token> LIKE LINE OF tokens,<cache> LIKE LINE OF mt_name_mappings.READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING <cache>.IF sy-subrc IS INITIAL.out = <cache>-json.ELSE.out = in.REPLACE ALL OCCURRENCES OF `__` IN out WITH `*`.TRANSLATE out TO LOWER CASE.TRANSLATE out USING `/_:_~_`.SPLIT out AT `_` INTO TABLE tokens.LOOP AT tokens ASSIGNING <token> FROM 2.TRANSLATE <token>(1) TO UPPER CASE.ENDLOOP.CONCATENATE LINES OF tokens INTO out.REPLACE ALL OCCURRENCES OF `*` IN out WITH `_`.cache-abap = in.cache-json = out.INSERT cache INTO TABLE mt_name_mappings.INSERT cache INTO TABLE mt_name_mappings_ex.ENDIF.ENDMETHOD. "PRETTY_NAME* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->PRETTY_NAME_EX
* +-------------------------------------------------------------------------------------------------+
* | [--->] IN TYPE CSEQUENCE
* | [<-()] OUT TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD pretty_name_ex.DATA: tokens TYPE TABLE OF char128,cache LIKE LINE OF mt_name_mappings.FIELD-SYMBOLS: <token> LIKE LINE OF tokens,<cache> LIKE LINE OF mt_name_mappings.READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING <cache>.IF sy-subrc IS INITIAL.out = <cache>-json.ELSE.out = in.TRANSLATE out TO LOWER CASE.TRANSLATE out USING `/_:_~_`.REPLACE ALL OCCURRENCES OF `__e__` IN out WITH `!`.REPLACE ALL OCCURRENCES OF `__n__` IN out WITH `#`.REPLACE ALL OCCURRENCES OF `__d__` IN out WITH `$`.REPLACE ALL OCCURRENCES OF `__p__` IN out WITH `%`.REPLACE ALL OCCURRENCES OF `__m__` IN out WITH `&`.REPLACE ALL OCCURRENCES OF `__s__` IN out WITH `*`.REPLACE ALL OCCURRENCES OF `__h__` IN out WITH `-`.REPLACE ALL OCCURRENCES OF `__t__` IN out WITH `~`.REPLACE ALL OCCURRENCES OF `__l__` IN out WITH `/`.REPLACE ALL OCCURRENCES OF `__c__` IN out WITH `:`.REPLACE ALL OCCURRENCES OF `__v__` IN out WITH `|`.REPLACE ALL OCCURRENCES OF `__a__` IN out WITH `@`.REPLACE ALL OCCURRENCES OF `__o__` IN out WITH `.`.REPLACE ALL OCCURRENCES OF `___` IN out WITH `.`.REPLACE ALL OCCURRENCES OF `__` IN out WITH `"`.SPLIT out AT `_` INTO TABLE tokens.LOOP AT tokens ASSIGNING <token> FROM 2.TRANSLATE <token>(1) TO UPPER CASE.ENDLOOP.CONCATENATE LINES OF tokens INTO out.REPLACE ALL OCCURRENCES OF `"` IN out WITH `_`.cache-abap = in.cache-json = out.INSERT cache INTO TABLE mt_name_mappings.INSERT cache INTO TABLE mt_name_mappings_ex.ENDIF.ENDMETHOD. "PRETTY_NAME_EX* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>RAW_TO_STRING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_XSTRING TYPE XSTRING
* | [--->] IV_ENCODING TYPE ABAP_ENCODING(optional)
* | [<-()] RV_STRING TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD raw_to_string.DATA: lv_output_length TYPE i,lt_binary_tab TYPE STANDARD TABLE OF sdokcntbin.CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'EXPORTINGbuffer = iv_xstringIMPORTINGoutput_length = lv_output_lengthTABLESbinary_tab = lt_binary_tab.CALL FUNCTION 'SCMS_BINARY_TO_STRING'EXPORTINGinput_length = lv_output_lengthencoding = iv_encodingIMPORTINGtext_buffer = rv_stringoutput_length = lv_output_lengthTABLESbinary_tab = lt_binary_tab.ENDMETHOD. "RAW_TO_STRING* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->RESTORE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON TYPE JSON
* | [--->] LENGTH TYPE I
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR(optional)
* | [--->] FIELD_CACHE TYPE T_T_FIELD_CACHE(optional)
* | [<-->] DATA TYPE DATA(optional)
* | [<-->] OFFSET TYPE I (default =0)
* | [!CX!] CX_SY_MOVE_CAST_ERROR
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD restore.DATA: mark LIKE offset,match LIKE offset,ref_descr TYPE REF TO cl_abap_refdescr,data_descr TYPE REF TO cl_abap_datadescr,data_ref TYPE REF TO data,object_ref TYPE REF TO object,fields LIKE field_cache,name_json TYPE string.FIELD-SYMBOLS: <value> TYPE any,<field_cache> LIKE LINE OF field_cache.DATA: BEGIN OF t_p_fields,name TYPE string,type TYPE REF TO cl_abap_datadescr,convexit_out TYPE string,convexit_in TYPE string,value TYPE REF TO data,END OF t_p_fields.DATA: p_fields LIKE TABLE OF t_p_fields.LOOP AT field_cache ASSIGNING <field_cache>.APPEND <field_cache> to p_fields.ENDLOOP.fields = field_cache.IF type_descr IS NOT INITIAL AND type_descr->kind EQ type_descr->kind_ref.ref_descr ?= type_descr.type_descr = ref_descr->get_referenced_type( ).IF ref_descr->type_kind EQ ref_descr->typekind_oref.IF data IS INITIAL." can fire an exception, if type is abstract or constructor protectedCREATE OBJECT data TYPE (type_descr->absolute_name).ENDIF.object_ref ?= data.fields = get_fields( type_descr = type_descr object = object_ref ).ELSEIF ref_descr->type_kind EQ ref_descr->typekind_dref.IF data IS INITIAL.data_descr ?= type_descr.CREATE DATA data TYPE HANDLE data_descr.ENDIF.data_ref ?= data.ASSIGN data_ref->* TO <value>.fields = get_fields( type_descr = type_descr data = data_ref ).restore( EXPORTING json = json length = length type_descr = type_descr field_cache = fieldsCHANGING data = <value> offset = offset ).RETURN.ENDIF.ENDIF.IF fields IS INITIAL AND type_descr IS NOT INITIAL AND type_descr->kind EQ type_descr->kind_struct.GET REFERENCE OF data INTO data_ref.fields = get_fields( type_descr = type_descr data = data_ref ).ENDIF.eat_white.eat_char `{`.eat_white.WHILE offset < length AND json+offset(1) NE `}`.eat_name name_json.eat_white.eat_char `:`.eat_white.READ TABLE fields WITH TABLE KEY name = name_json ASSIGNING <field_cache>.IF sy-subrc IS NOT INITIAL.TRANSLATE name_json TO UPPER CASE.READ TABLE fields WITH TABLE KEY name = name_json ASSIGNING <field_cache>.ENDIF.IF sy-subrc IS INITIAL.ASSIGN <field_cache>-value->* TO <value>.restore_type( EXPORTING json = json length = length type_descr = <field_cache>-type convexit = <field_cache>-convexit_in CHANGING data = <value> offset = offset ).ELSE.restore_type( EXPORTING json = json length = length CHANGING offset = offset ).ENDIF.eat_white.IF offset < length AND json+offset(1) NE `}`.eat_char `,`.eat_white.ELSE.EXIT.ENDIF.ENDWHILE.eat_char `}`.ENDMETHOD. "RESTORE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Protected Method ZCL_JSON->RESTORE_TYPE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON TYPE JSON
* | [--->] LENGTH TYPE I
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR(optional)
* | [--->] FIELD_CACHE TYPE T_T_FIELD_CACHE(optional)
* | [--->] CONVEXIT TYPE STRING(optional)
* | [<-->] DATA TYPE DATA(optional)
* | [<-->] OFFSET TYPE I (default =0)
* | [!CX!] CX_SY_MOVE_CAST_ERROR
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD restore_type.DATA: mark LIKE offset,match LIKE offset,sdummy TYPE string, "#EC NEEDEDrdummy TYPE REF TO data, "#EC NEEDEDpos LIKE offset,line TYPE REF TO data,key_ref TYPE REF TO data,data_ref TYPE REF TO data,key_name TYPE string,key_value TYPE string,lt_fields LIKE field_cache,lt_symbols TYPE t_t_symbol,lv_ticks TYPE string,lv_offset TYPE string,lv_convexit LIKE convexit,lo_exp TYPE REF TO cx_root,elem_descr TYPE REF TO cl_abap_elemdescr,table_descr TYPE REF TO cl_abap_tabledescr,data_descr TYPE REF TO cl_abap_datadescr.FIELD-SYMBOLS: <line> TYPE any,<value> TYPE any,<data> TYPE data,<field> LIKE LINE OF lt_fields,<table> TYPE ANY TABLE,<value_sym> LIKE LINE OF lt_symbols.lv_convexit = convexit.IF type_descr IS INITIAL AND data IS SUPPLIED.type_descr = cl_abap_typedescr=>describe_by_data( data ).IF mv_conversion_exits EQ abap_true AND lv_convexit IS INITIAL AND type_descr->kind EQ cl_abap_typedescr=>kind_elem.elem_descr ?= type_descr.lv_convexit = get_convexit_func( elem_descr = elem_descr input = abap_true ).ENDIF.ENDIF.eat_white.TRY .IF type_descr IS NOT INITIAL AND type_descr->absolute_name EQ mc_json_type." skip deserializationmark = offset.restore_type( EXPORTING json = json length = length CHANGING offset = offset ).match = offset - mark.data = json+mark(match).ENDIF.CASE json+offset(1).WHEN `{`. " objectIF type_descr IS NOT INITIAL.IF mv_assoc_arrays EQ c_bool-true AND type_descr->kind EQ cl_abap_typedescr=>kind_table.table_descr ?= type_descr.data_descr = table_descr->get_table_line_type( ).IF table_descr->has_unique_key IS NOT INITIAL.eat_char `{`.eat_white.IF json+offset(1) NE `}`.ASSIGN data TO <table>.CLEAR <table>.CREATE DATA line LIKE LINE OF <table>.ASSIGN line->* TO <line>.lt_fields = get_fields( type_descr = data_descr data = line ).IF table_descr->key_defkind EQ table_descr->keydefkind_user AND lines( table_descr->key ) EQ 1.READ TABLE table_descr->key INDEX 1 INTO key_name.READ TABLE lt_fields WITH TABLE KEY name = key_name ASSIGNING <field>.key_ref = <field>-value.IF mv_assoc_arrays_opt EQ c_bool-true.lt_symbols = get_symbols( type_descr = data_descr data = line ).DELETE lt_symbols WHERE name EQ key_name.IF lines( lt_symbols ) EQ 1.READ TABLE lt_symbols INDEX 1 ASSIGNING <value_sym>.ENDIF.ENDIF.ENDIF.eat_white.WHILE offset < length AND json+offset(1) NE `}`.CLEAR <line>.eat_name key_value.eat_white.eat_char `:`.eat_white.IF <value_sym> IS ASSIGNED.ASSIGN <value_sym>-value->* TO <value>.restore_type( EXPORTING json = json length = length type_descr = <value_sym>-type convexit = <value_sym>-convexit_inCHANGING data = <value> offset = offset ).ELSE.restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fieldsCHANGING data = <line> offset = offset ).ENDIF.IF table_descr->key_defkind EQ table_descr->keydefkind_user.IF key_ref IS BOUND.ASSIGN key_ref->* TO <value>.IF <value> IS INITIAL.<value> = key_value.ENDIF.ENDIF.ELSEIF <line> IS INITIAL.<line> = key_value.ENDIF.INSERT <line> INTO TABLE <table>.eat_white.IF offset < length AND json+offset(1) NE `}`.eat_char `,`.eat_white.ELSE.EXIT.ENDIF.ENDWHILE.ELSE.CLEAR data.ENDIF.eat_char `}`.ELSE.restore( EXPORTING json = json length = length CHANGING offset = offset ).ENDIF.ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref.IF data IS INITIAL.generate_int_ex( EXPORTING json = json length = length CHANGING offset = offset data = data ).ELSE.data_ref ?= data.type_descr = cl_abap_typedescr=>describe_by_data_ref( data_ref ).ASSIGN data_ref->* TO <data>.restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING data = <data> offset = offset ).ENDIF.ELSE.restore( EXPORTING json = json length = length type_descr = type_descr field_cache = field_cacheCHANGING data = data offset = offset ).ENDIF.ELSE.restore( EXPORTING json = json length = length CHANGING offset = offset ).ENDIF.WHEN `[`. " arrayIF type_descr IS NOT INITIAL AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref.IF data IS INITIAL.generate_int_ex( EXPORTING json = json length = length CHANGING offset = offset data = data ).ELSE.data_ref ?= data.type_descr = cl_abap_typedescr=>describe_by_data_ref( data_ref ).ASSIGN data_ref->* TO <data>.restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING data = <data> offset = offset ).ENDIF.ELSE.eat_char `[`.eat_white.IF json+offset(1) NE `]`.IF type_descr IS NOT INITIAL AND type_descr->kind EQ cl_abap_typedescr=>kind_table.table_descr ?= type_descr.data_descr = table_descr->get_table_line_type( ).ASSIGN data TO <table>.CLEAR <table>.CREATE DATA line LIKE LINE OF <table>.ASSIGN line->* TO <line>.lt_fields = get_fields( type_descr = data_descr data = line ).WHILE offset < length AND json+offset(1) NE `]`.CLEAR <line>.restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fieldsCHANGING data = <line> offset = offset ).INSERT <line> INTO TABLE <table>.eat_white.IF offset < length AND json+offset(1) NE `]`.eat_char `,`.eat_white.ELSE.EXIT.ENDIF.ENDWHILE.ELSE." skip arrayeat_white.WHILE offset < length AND json+offset(1) NE `]`.restore_type( EXPORTING json = json length = length CHANGING offset = offset ).eat_white.IF offset < length AND json+offset(1) NE `]`.eat_char `,`.eat_white.ELSE.EXIT.ENDIF.ENDWHILE.IF type_descr IS NOT INITIAL.eat_char `]`.throw_error.ENDIF.ENDIF.ELSE.CLEAR data.ENDIF.eat_char `]`.ENDIF.WHEN `"`. " stringeat_string sdummy.IF type_descr IS NOT INITIAL." unescape stringIF sdummy IS NOT INITIAL.IF type_descr->kind EQ cl_abap_typedescr=>kind_elem.elem_descr ?= type_descr.IF lv_convexit IS NOT INITIAL.TRY .CALL FUNCTION lv_convexitEXPORTINGinput = sdummyIMPORTINGoutput = dataEXCEPTIONSerror_message = 2OTHERS = 1.IF sy-subrc IS INITIAL.RETURN.ENDIF.CATCH cx_root. "#EC NO_HANDLERENDTRY.ENDIF.CASE elem_descr->type_kind.WHEN cl_abap_typedescr=>typekind_char.IF elem_descr->output_length EQ 1 AND mc_bool_types CS elem_descr->absolute_name.IF sdummy(1) CA `XxTt1`.data = c_bool-true.ELSE.data = c_bool-false.ENDIF.RETURN.ENDIF.WHEN cl_abap_typedescr=>typekind_xstring.string_to_xstring( EXPORTING in = sdummy CHANGING out = data ).RETURN.WHEN cl_abap_typedescr=>typekind_hex." support for Edm.GuidREPLACE FIRST OCCURRENCE OF REGEX `^([0-9A-F]{8})-([0-9A-F]{4})-([0-9A-F]{4})-([0-9A-F]{4})-([0-9A-F]{12})$` IN sdummyWITH `$1$2$3$4$5` REPLACEMENT LENGTH match. "#EC NOTEXTIF sy-subrc EQ 0.data = sdummy(match).ELSE.string_to_xstring( EXPORTING in = sdummy CHANGING out = data ).ENDIF.RETURN.WHEN cl_abap_typedescr=>typekind_date." support for ISO8601 => https://en.wikipedia.org/wiki/ISO_8601REPLACE FIRST OCCURRENCE OF REGEX `^(\d{4})-(\d{2})-(\d{2})` IN sdummy WITH `$1$2$3`REPLACEMENT LENGTH match. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = sdummy(match).ELSE." support for Edm.DateTime => http://www.odata.org/documentation/odata-version-2-0/json-format/FIND FIRST OCCURRENCE OF REGEX `^\/Date\((-?\d+)([+-]\d{1,4})?\)\/` IN sdummy SUBMATCHES lv_ticks lv_offset IGNORING CASE. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = edm_datetime_to_ts( ticks = lv_ticks offset = lv_offset typekind = elem_descr->type_kind ).ELSE." support for Edm.Time => https://www.w3.org/TR/xmlschema11-2/#nt-durationRepREPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$1$2$3`REPLACEMENT LENGTH match. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = sdummy(match).ENDIF.ENDIF.ENDIF.WHEN cl_abap_typedescr=>typekind_time." support for ISO8601 => https://en.wikipedia.org/wiki/ISO_8601REPLACE FIRST OCCURRENCE OF REGEX `^(\d{2}):(\d{2}):(\d{2})` IN sdummy WITH `$1$2$3`REPLACEMENT LENGTH match. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = sdummy(match).ELSE." support for Edm.DateTime => http://www.odata.org/documentation/odata-version-2-0/json-format/FIND FIRST OCCURRENCE OF REGEX '^\/Date\((-?\d+)([+-]\d{1,4})?\)\/' IN sdummy SUBMATCHES lv_ticks lv_offset IGNORING CASE. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = edm_datetime_to_ts( ticks = lv_ticks offset = lv_offset typekind = elem_descr->type_kind ).ELSE." support for Edm.Time => https://www.w3.org/TR/xmlschema11-2/#nt-durationRepREPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$4$5$6`REPLACEMENT LENGTH match. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = sdummy(match).ENDIF.ENDIF.ENDIF.WHEN cl_abap_typedescr=>typekind_packed.REPLACE FIRST OCCURRENCE OF REGEX `^(\d{4})-?(\d{2})-?(\d{2})T(\d{2}):?(\d{2}):?(\d{2})(?:[\.,](\d{0,7}))?Z?` IN sdummy WITH `$1$2$3$4$5$6.$7`REPLACEMENT LENGTH match. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = sdummy(match).ELSE.FIND FIRST OCCURRENCE OF REGEX '^\/Date\((-?\d+)([+-]\d{1,4})?\)\/' IN sdummy SUBMATCHES lv_ticks lv_offset IGNORING CASE. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = edm_datetime_to_ts( ticks = lv_ticks offset = lv_offset typekind = elem_descr->type_kind ).ELSE." support for Edm.Time => https://www.w3.org/TR/xmlschema11-2/#nt-durationRepREPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$1$2$3$4$5$6.$7`REPLACEMENT LENGTH match. "#EC NOTEXTIF sy-subrc EQ 0.sdummy = sdummy(match).ENDIF.ENDIF.ENDIF.WHEN `k`. "cl_abap_typedescr=>typekind_enumTRY.CALL METHOD ('CL_ABAP_XSD')=>('TO_VALUE')EXPORTINGcs = sdummyCHANGINGval = data.RETURN.CATCH cx_sy_dyn_call_error.throw_error. " Deserialization of enums is not supportedENDTRY.ENDCASE.ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref.CREATE DATA rdummy TYPE string.ASSIGN rdummy->* TO <data>.<data> = sdummy.data ?= rdummy.RETURN.ELSE.throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTEDENDIF.data = sdummy.ELSEIF type_descr->kind EQ cl_abap_typedescr=>kind_elem.CLEAR data.ELSE.throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTEDENDIF.ENDIF.WHEN `-` OR `0` OR `1` OR `2` OR `3` OR `4` OR `5` OR `6` OR `7` OR `8` OR `9`. " numberIF type_descr IS NOT INITIAL.IF type_descr->kind EQ type_descr->kind_ref AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref.eat_number sdummy. "#EC NOTEXTmatch = strlen( sdummy ).IF sdummy CS '.'. " float.CREATE DATA rdummy TYPE f.ELSEIF match GT 9. " packedCREATE DATA rdummy TYPE p.ELSE. " integerCREATE DATA rdummy TYPE i.ENDIF.ASSIGN rdummy->* TO <data>.<data> = sdummy.data ?= rdummy.ELSEIF type_descr->kind EQ type_descr->kind_elem.IF lv_convexit IS NOT INITIAL.TRY .eat_number sdummy. "#EC NOTEXTCALL FUNCTION lv_convexitEXPORTINGinput = sdummyIMPORTINGoutput = dataEXCEPTIONSerror_message = 2OTHERS = 1.IF sy-subrc IS INITIAL.RETURN.ENDIF.CATCH cx_root. "#EC NO_HANDLERENDTRY.ENDIF.eat_number data. "#EC NOTEXTELSE.eat_number sdummy. "#EC NOTEXTthrow_error.ENDIF.ELSE.eat_number sdummy. "#EC NOTEXTENDIF.WHEN OTHERS. " boolean, e.g true/false/nullIF type_descr IS NOT INITIAL.IF type_descr->kind EQ type_descr->kind_ref AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref.CREATE DATA rdummy TYPE bool.ASSIGN rdummy->* TO <data>.eat_bool <data>. "#EC NOTEXTdata ?= rdummy.ELSEIF type_descr->kind EQ type_descr->kind_elem.eat_bool data. "#EC NOTEXTELSE.eat_bool sdummy. "#EC NOTEXTthrow_error.ENDIF.ELSE.eat_bool sdummy. "#EC NOTEXTENDIF.ENDCASE.CATCH cx_sy_move_cast_error cx_sy_conversion_no_number cx_sy_conversion_overflow INTO lo_exp.CLEAR data.IF mv_strict_mode EQ abap_true.RAISE EXCEPTION TYPE cx_sy_move_cast_errorEXPORTINGprevious = lo_exp.ENDIF.ENDTRY.ENDMETHOD. "RESTORE_TYPE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>SERIALIZE
* +-------------------------------------------------------------------------------------------------+
* | [--->] DATA TYPE DATA
* | [--->] COMPRESS TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] NAME TYPE STRING(optional)
* | [--->] PRETTY_NAME TYPE PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR(optional)
* | [--->] ASSOC_ARRAYS TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] TS_AS_ISO8601 TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] EXPAND_INCLUDES TYPE BOOL (default =C_BOOL-TRUE)
* | [--->] ASSOC_ARRAYS_OPT TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] NUMC_AS_STRING TYPE BOOL (default =C_BOOL-FALSE)
* | [--->] NAME_MAPPINGS TYPE NAME_MAPPINGS(optional)
* | [--->] CONVERSION_EXITS TYPE BOOL (default =C_BOOL-FALSE)
* | [<-()] R_JSON TYPE JSON
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD serialize." **********************************************************************" Usage examples and documentation can be found on SCN:" http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer" ********************************************************************** "DATA: lo_json TYPE REF TO zcl_json.CREATE OBJECT lo_jsonEXPORTINGcompress = compresspretty_name = pretty_namename_mappings = name_mappingsassoc_arrays = assoc_arraysassoc_arrays_opt = assoc_arrays_optexpand_includes = expand_includesnumc_as_string = numc_as_stringconversion_exits = conversion_exitsts_as_iso8601 = ts_as_iso8601.r_json = lo_json->serialize_int( name = name data = data type_descr = type_descr ).ENDMETHOD. "SERIALIZE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_JSON->SERIALIZE_INT
* +-------------------------------------------------------------------------------------------------+
* | [--->] DATA TYPE DATA
* | [--->] NAME TYPE STRING(optional)
* | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR(optional)
* | [<-()] R_JSON TYPE JSON
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD serialize_int." **********************************************************************" Usage examples and documentation can be found on SCN:" http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer" ********************************************************************** "DATA: lo_descr TYPE REF TO cl_abap_typedescr,lo_elem_descr TYPE REF TO cl_abap_elemdescr,lv_convexit TYPE string.IF type_descr IS INITIAL.lo_descr = cl_abap_typedescr=>describe_by_data( data ).ELSE.lo_descr = type_descr.ENDIF.IF mv_conversion_exits EQ abap_true AND lo_descr->kind EQ cl_abap_typedescr=>kind_elem.lo_elem_descr ?= lo_descr.lv_convexit = get_convexit_func( elem_descr = lo_elem_descr input = abap_false ).ENDIF.r_json = dump_int( data = data type_descr = lo_descr convexit = lv_convexit )." we do not do escaping of every single string value for white space characters," but we do it on top, to replace multiple calls by 3 only, while we do not serialize" outlined/formatted JSON this shall not produce any harmREPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf IN r_json WITH `\r\n`.REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline IN r_json WITH `\n`.REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab IN r_json WITH `\t`.
* REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>form_feed IN r_json WITH `\f`.
* REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>backspace IN r_json WITH `\b`.IF name IS NOT INITIAL AND ( mv_compress IS INITIAL OR r_json IS NOT INITIAL ).CONCATENATE `"` name `":` r_json INTO r_json.ENDIF.ENDMETHOD. "SERIALIZE_INT* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>STRING_TO_RAW
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_STRING TYPE STRING
* | [--->] IV_ENCODING TYPE ABAP_ENCODING(optional)
* | [<-()] RV_XSTRING TYPE XSTRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD string_to_raw.CALL FUNCTION 'SCMS_STRING_TO_XSTRING'EXPORTINGtext = iv_stringencoding = iv_encodingIMPORTINGbuffer = rv_xstringEXCEPTIONSOTHERS = 1.IF sy-subrc IS NOT INITIAL.CLEAR rv_xstring.ENDIF.ENDMETHOD. "STRING_TO_RAW* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>STRING_TO_XSTRING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IN TYPE STRING
* | [<-->] OUT TYPE ANY
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD string_to_xstring.DATA: lv_xstring TYPE xstring.CALL FUNCTION 'SSFC_BASE64_DECODE'EXPORTINGb64data = inIMPORTINGbindata = lv_xstringEXCEPTIONSOTHERS = 1.IF sy-subrc IS INITIAL.out = lv_xstring.ELSE.out = in.ENDIF.ENDMETHOD. "STRING_TO_XSTRING* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>TRIBOOL_TO_BOOL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_TRIBOOL TYPE TRIBOOL
* | [<-()] RV_BOOL TYPE BOOL
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD tribool_to_bool.IF iv_tribool EQ c_tribool-true.rv_bool = c_bool-true.ELSEIF iv_tribool EQ c_tribool-undefined.rv_bool = abap_undefined. " fall back to abap_undefinedENDIF.ENDMETHOD. "TRIBOOL_TO_BOOL* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Protected Method ZCL_JSON=>UNESCAPE
* +-------------------------------------------------------------------------------------------------+
* | [--->] ESCAPED TYPE STRING
* | [<-()] UNESCAPED TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD unescape.DATA: lv_offset TYPE i,lv_match TYPE i,lv_delta TYPE i,lv_length TYPE i,lv_offset_e TYPE i,lv_length_e TYPE i,lv_unicode_symb TYPE c,lv_unicode_escaped TYPE string,lt_matches TYPE match_result_tab.FIELD-SYMBOLS: <match> LIKE LINE OF lt_matches." see reference for escaping rules in JSON RFC" https://www.ietf.org/rfc/rfc4627.txtunescaped = escaped.lv_length = strlen( unescaped ).FIND FIRST OCCURRENCE OF REGEX `\\[rntfbu]` IN unescaped RESPECTING CASE.IF sy-subrc IS INITIAL.FIND ALL OCCURRENCES OF REGEX `\\.` IN unescaped RESULTS lt_matches RESPECTING CASE.LOOP AT lt_matches ASSIGNING <match>.lv_match = <match>-offset - lv_delta.lv_offset = lv_match + 1.CASE unescaped+lv_offset(1).WHEN `r`.REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>cr_lf(1).lv_delta = lv_delta + 1.WHEN `n`.REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>newline.lv_delta = lv_delta + 1.WHEN `t`.REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>horizontal_tab.lv_delta = lv_delta + 1.WHEN `f`.REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>form_feed.lv_delta = lv_delta + 1.WHEN `b`.REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>backspace.lv_delta = lv_delta + 1.WHEN `u`.lv_offset = lv_offset + 1.lv_offset_e = lv_offset + 4.lv_length_e = lv_length + lv_delta.IF lv_offset_e LE lv_length_e.lv_unicode_escaped = unescaped+lv_offset(4).TRANSLATE lv_unicode_escaped TO UPPER CASE.lv_unicode_symb = cl_abap_conv_in_ce=>uccp( lv_unicode_escaped ).IF lv_unicode_symb NE mc_cov_error.REPLACE SECTION OFFSET lv_match LENGTH 6 OF unescaped WITH lv_unicode_symb.lv_delta = lv_delta + 5.ENDIF.ENDIF.ENDCASE.ENDLOOP.ENDIF." based on RFC mentioned above, _any_ character can be escaped, and so shall be enscaped" the only exception is Unicode symbols, that shall be kept untouched, while serializer does not handle them" unescaped singe characters, e.g \\, \", \/ etcREPLACE ALL OCCURRENCES OF REGEX `\\(.)` IN unescaped WITH `$1` RESPECTING CASE.ENDMETHOD. "UNESCAPE* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>XSTRING_TO_STRING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IN TYPE ANY
* | [<-()] OUT TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>METHOD xstring_to_string.DATA: lv_xstring TYPE xstring." let us fix data conversion issues herelv_xstring = in.CALL FUNCTION 'SSFC_BASE64_ENCODE'EXPORTINGbindata = lv_xstringIMPORTINGb64data = outEXCEPTIONSOTHERS = 1.IF sy-subrc IS NOT INITIAL.out = in.ENDIF.ENDMETHOD. "XSTRING_TO_STRING
ENDCLASS.
点击下图红框按钮。
复制粘贴下面代码
*"* use this source file for the definition and implementation of
*"* local helper classes, interface definitions and type
*"* declarations*"* local class implementation for public class
*"* use this source file for the implementation part of
*"* local helper classesDEFINE escape_json_inplace.
* replace all occurrences of regex `[\\"]` in &1 with `\\$0`. <-- this is slower than 2 plain replacesreplace all occurrences of `\` in &1 with `\\`.replace all occurrences of `"` in &1 with `\"`.
END-OF-DEFINITION.DEFINE escape_json.&2 = &1.escape_json_inplace &2.
END-OF-DEFINITION.DEFINE is_compressable.if mv_extended is initial.&3 = abap_true.else.&3 = is_compressable( type_descr = &1 name = &2 ).endif.
END-OF-DEFINITION.DEFINE dump_type.if mv_extended is initial.dump_type_int &1 &2 &3 &4.else.&3 = dump_type( data = &1 type_descr = &2 convexit = &4 ).endif.
END-OF-DEFINITION.DEFINE dump_type_int.if &4 is not initial and &1 is not initial.try.call function &4exportinginput = &1importingoutput = &3exceptionsothers = 1.if sy-subrc is initial.concatenate `"` &3 `"` into &3.endif.catch cx_root. "#EC NO_HANDLERendtry.else.case &2->type_kind.when cl_abap_typedescr=>typekind_float or cl_abap_typedescr=>typekind_int or cl_abap_typedescr=>typekind_int1 orcl_abap_typedescr=>typekind_int2 or cl_abap_typedescr=>typekind_packed or `8`. " TYPEKIND_INT8 -> '8' only from 7.40.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*`.if &1 is initial.&3 = `""`.else.&3 = &1.if &2->absolute_name eq `\TYPE=TIMESTAMP`.concatenate `"` &3(4) `-` &3+4(2) `-` &3+6(2) `T` &3+8(2) `:` &3+10(2) `:` &3+12(2) `.0000000Z"` into &3.elseif &2->absolute_name eq `\TYPE=TIMESTAMPL`.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.endif.endif.elseif &1 is initial.&3 = `0`.else.&3 = &1.if &1 lt 0.if &2->type_kind <> cl_abap_typedescr=>typekind_float. "float: sign is already at the beginningshift &3 right circular.endif.else.condense &3.endif.endif.when cl_abap_typedescr=>typekind_num.if mv_numc_as_string eq abap_true.if &1 is initial.&3 = `""`.else.concatenate `"` &1 `"` into &3.endif.else.&3 = &1.shift &3 left deleting leading ` 0`.if &3 is initial.&3 = `0`.endif.endif.when cl_abap_typedescr=>typekind_string or cl_abap_typedescr=>typekind_csequence or cl_abap_typedescr=>typekind_clike.if &1 is initial.&3 = `""`.elseif &2->absolute_name eq mc_json_type.&3 = &1.else.escape_json &1 &3.concatenate `"` &3 `"` into &3.endif.when cl_abap_typedescr=>typekind_xstring or cl_abap_typedescr=>typekind_hex.if &1 is initial.&3 = `""`.else.&3 = xstring_to_string( &1 ).escape_json_inplace &3.concatenate `"` &3 `"` into &3.endif.when cl_abap_typedescr=>typekind_char.if &2->output_length eq 1 and mc_bool_types cs &2->absolute_name.if &1 eq c_bool-true.&3 = `true`. "#EC NOTEXTelseif mc_bool_3state cs &2->absolute_name and &1 is initial.&3 = `null`. "#EC NOTEXTelse.&3 = `false`. "#EC NOTEXTendif.else.escape_json &1 &3.concatenate `"` &3 `"` into &3.endif.when cl_abap_typedescr=>typekind_date.concatenate `"` &1(4) `-` &1+4(2) `-` &1+6(2) `"` into &3.when cl_abap_typedescr=>typekind_time.concatenate `"` &1(2) `:` &1+2(2) `:` &1+4(2) `"` into &3.when `k`. " cl_abap_typedescr=>typekind_enum&3 = &1.concatenate `"` &3 `"` into &3.when others.if &1 is initial.&3 = `null`. "#EC NOTEXTelse.&3 = &1.endif.endcase.endif.END-OF-DEFINITION.DEFINE format_name.case &2.when pretty_mode-camel_case.&3 = pretty_name( &1 ).when pretty_mode-extended.&3 = pretty_name_ex( &1 ).when pretty_mode-user_low_case.read table mt_name_mappings with table key abap = &1 assigning <cache>. "#EC WARNOKif sy-subrc is initial.&3 = <cache>-json.else.&3 = &1.translate &3 to lower case. "#EC SYNTCHARendif.when pretty_mode-user.read table mt_name_mappings with table key abap = &1 assigning <cache>. "#EC WARNOKif sy-subrc is initial.&3 = <cache>-json.else.&3 = &1.endif.when pretty_mode-low_case.&3 = &1.translate &3 to lower case. "#EC SYNTCHARwhen others.&3 = &1.endcase.
END-OF-DEFINITION.DEFINE throw_error.raise exception type cx_sy_move_cast_error.
END-OF-DEFINITION.DEFINE while_offset_cs.
* >= 7.02 alternative
* pos = find_any_not_of( val = json sub = &1 off = offset ).
* if pos eq -1. offset = length.
* else. offset = pos. endif.* < 7.02while offset < length.find first occurrence of json+offset(1) in &1.if sy-subrc is not initial.exit.endif.offset = offset + 1.endwhile.
* < 7.02END-OF-DEFINITION.DEFINE while_offset_not_cs.while offset < length.find first occurrence of &2+offset(1) in &1.if sy-subrc is initial.exit.endif.offset = offset + 1.endwhile.
END-OF-DEFINITION.DEFINE eat_white.while_offset_cs sv_white_space.if offset ge length.throw_error.endif.
END-OF-DEFINITION.DEFINE eat_name.if json+offset(1) eq `"`.mark = offset + 1.offset = mark.find first occurrence of `"` in section offset offset of json match offset offset.if sy-subrc is not initial.throw_error.endif.match = offset - mark.&1 = json+mark(match).offset = offset + 1.else.throw_error.endif.
END-OF-DEFINITION.DEFINE eat_string.if json+offset(1) eq `"`.mark = offset + 1.offset = mark.do.find first occurrence of `"` in section offset offset of json match offset pos.if sy-subrc is not initial.throw_error.endif.offset = pos.pos = pos - 1." if escaped search furtherwhile pos ge 0 and json+pos(1) eq `\`.pos = pos - 1.endwhile.match = ( offset - pos ) mod 2.if match ne 0.exit.endif.offset = offset + 1.enddo.match = offset - mark.&1 = json+mark(match)." unescaped singe characters, e.g \\, \", \/ etc," BUT ONLY if someone really need the dataif type_descr is not initial.&1 = unescape( &1 ).endif.offset = offset + 1.else.throw_error.endif.
END-OF-DEFINITION.DEFINE eat_number.mark = offset.while_offset_cs `0123456789+-eE.`. "#EC NOTEXTmatch = offset - mark.&1 = json+mark(match).
END-OF-DEFINITION.DEFINE eat_bool.mark = offset.while_offset_cs `aeflnrstu`. "#EC NOTEXTmatch = offset - mark.if json+mark(match) eq `true`. "#EC NOTEXT&1 = c_bool-true.elseif json+mark(match) eq `false`. "#EC NOTEXTif type_descr is bound and mc_bool_3state cs type_descr->absolute_name.&1 = c_tribool-false.else.&1 = c_bool-false.endif.elseif json+mark(match) eq `null`. "#EC NOTEXTclear &1.endif.
END-OF-DEFINITION.DEFINE eat_char.if offset < length and json+offset(1) eq &1.offset = offset + 1.else.throw_error.endif.
END-OF-DEFINITION.
激活,至此完成。
可用下面代码测试。
REPORT zrtest2NO STANDARD PAGE HEADING LINE-SIZE 255.data: lv_json_str type string.data: begin of ls_data,matnr like mara-matnr,end of ls_data.data: ls_data2 like ls_data.ls_data-matnr = '20231106'.CALL METHOD zcl_json=>serializeEXPORTINGdata = ls_data"pretty_name = iv_pretty_namenumc_as_string = 'X'RECEIVINGr_json = lv_json_str.CALL METHOD zcl_json=>deserializeEXPORTINGjson = lv_json_strCHANGINGdata = ls_data2.if sy-subrc = 0.endif.
测试结果