最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

SAP根据源码导入/ui2/cl_json类

来源:博客园


(相关资料图)

之前我都是用CALL TRANSFORMATION id方式来解析json数据的,结果发现解析出来的的数据有问题。无奈之下只好使用/ui2/cl_json类方法了,结果发现SAP版本不够,没有这个方法,网上找到源码不知道如何使用,总不可能我手动一个一个建方法和属性吧。然后找啊找,终于找到一种方法了。新建一个se38程序,把源码放到里,源码如下。

*----------------------------------------------------------------------**       CLASS zcl_json DEFINITION*----------------------------------------------------------------------***----------------------------------------------------------------------* CLASS zcl_json DEFINITION.   PUBLIC SECTION.    TYPE-POOLS abap .    CLASS cl_abap_tstmp DEFINITION LOAD .    CLASS cx_sy_conversion_error DEFINITION LOAD .     TYPES:      json TYPE string,      BEGIN OF name_mapping,        abap TYPE abap_compname,        json TYPE string,      END OF name_mapping,      name_mappings    TYPE HASHED TABLE OF name_mapping WITH UNIQUE KEY abap,      ref_tab          TYPE STANDARD TABLE OF REF TO data WITH DEFAULT KEY,      bool             TYPE char1,      tribool          TYPE char1,      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,      BEGIN OF c_bool,        true  TYPE bool  VALUE `X`,        false TYPE bool  VALUE ``,      END OF  c_bool,      BEGIN OF c_tribool,        true      TYPE tribool  VALUE c_bool-true,        false     TYPE tribool  VALUE `-`,        undefined TYPE tribool  VALUE ``,      END OF  c_tribool,      mc_key_separator TYPE string VALUE `-`,               "#EC NOTEXT      version          TYPE i VALUE 15.                     "#EC NOTEXT     CLASS-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_xstring      IMPORTING        in         TYPE string      CHANGING        VALUE(out) TYPE any .    CLASS-METHODS xstring_to_string      IMPORTING        in         TYPE any      RETURNING        VALUE(out) TYPE string .    CLASS-METHODS raw_to_string      IMPORTING        iv_xstring       TYPE xstring        iv_encoding      TYPE abap_encoding OPTIONAL      RETURNING        VALUE(rv_string) TYPE string .    CLASS-METHODS string_to_raw      IMPORTING        iv_string         TYPE string        iv_encoding       TYPE abap_encoding OPTIONAL      RETURNING        VALUE(rv_xstring) TYPE xstring .    CLASS-METHODS deserialize      IMPORTING        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      CHANGING        data             TYPE data .    CLASS-METHODS serialize      IMPORTING        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      RETURNING        VALUE(r_json)    TYPE json .    METHODS deserialize_int      IMPORTING        json  TYPE json OPTIONAL        jsonx TYPE xstring OPTIONAL      CHANGING        data  TYPE data      RAISING        cx_sy_move_cast_error .    CLASS-METHODS generate      IMPORTING        json           TYPE json        pretty_name    TYPE pretty_name_mode DEFAULT pretty_mode-none        name_mappings  TYPE name_mappings OPTIONAL      RETURNING        VALUE(rr_data) TYPE REF TO data .    METHODS serialize_int      IMPORTING        data          TYPE data        name          TYPE string OPTIONAL        type_descr    TYPE REF TO cl_abap_typedescr OPTIONAL      RETURNING        VALUE(r_json) TYPE json .    METHODS generate_int      IMPORTING        json           TYPE json        VALUE(length)  TYPE i OPTIONAL      RETURNING        VALUE(rr_data) TYPE REF TO data      RAISING        cx_sy_move_cast_error .    METHODS constructor      IMPORTING        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_tribool      IMPORTING        iv_bool           TYPE bool      RETURNING        VALUE(rv_tribool) TYPE tribool .    CLASS-METHODS tribool_to_bool      IMPORTING        iv_tribool     TYPE tribool      RETURNING        VALUE(rv_bool) TYPE bool .   PROTECTED SECTION.     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 unescape      IMPORTING        escaped          TYPE string      RETURNING        VALUE(unescaped) TYPE string .    CLASS-METHODS get_convexit_func      IMPORTING        elem_descr     TYPE REF TO cl_abap_elemdescr        input          TYPE abap_bool OPTIONAL      RETURNING        VALUE(rv_func) TYPE string .    METHODS dump_symbols FINAL      IMPORTING        it_symbols    TYPE t_t_symbol      RETURNING        VALUE(r_json) TYPE json .    METHODS get_symbols FINAL      IMPORTING        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      RETURNING        VALUE(result)   TYPE t_t_symbol .    METHODS get_fields FINAL      IMPORTING        type_descr       TYPE REF TO cl_abap_typedescr        data             TYPE REF TO data OPTIONAL        object           TYPE REF TO object OPTIONAL      RETURNING        VALUE(rt_fields) TYPE t_t_field_cache .    METHODS dump_int      IMPORTING        data          TYPE data        type_descr    TYPE REF TO cl_abap_typedescr OPTIONAL        convexit      TYPE string OPTIONAL      RETURNING        VALUE(r_json) TYPE json .    METHODS is_compressable      IMPORTING        type_descr         TYPE REF TO cl_abap_typedescr        name               TYPE csequence      RETURNING        VALUE(rv_compress) TYPE abap_bool .    METHODS restore      IMPORTING        json              TYPE json        length            TYPE i        VALUE(type_descr) TYPE REF TO cl_abap_typedescr OPTIONAL        field_cache       TYPE t_t_field_cache OPTIONAL      CHANGING        data              TYPE data OPTIONAL        offset            TYPE i DEFAULT 0      RAISING        cx_sy_move_cast_error .    METHODS restore_type      IMPORTING        json              TYPE json        length            TYPE i        VALUE(type_descr) TYPE REF TO cl_abap_typedescr OPTIONAL        field_cache       TYPE t_t_field_cache OPTIONAL        convexit          TYPE string OPTIONAL      CHANGING        data              TYPE data OPTIONAL        offset            TYPE i DEFAULT 0      RAISING        cx_sy_move_cast_error .    METHODS dump_type      IMPORTING        data          TYPE data        type_descr    TYPE REF TO cl_abap_elemdescr        convexit      TYPE string      RETURNING        VALUE(r_json) TYPE json .    METHODS pretty_name_ex      IMPORTING        in         TYPE csequence      RETURNING        VALUE(out) TYPE string .    METHODS generate_int_ex FINAL      IMPORTING        json   TYPE json        length TYPE i      CHANGING        data   TYPE data        offset TYPE i .    METHODS pretty_name      IMPORTING        in         TYPE csequence      RETURNING        VALUE(out) TYPE string .    CLASS-METHODS escape      IMPORTING        in         TYPE any      RETURNING        VALUE(out) TYPE string .    CLASS-METHODS edm_datetime_to_ts      IMPORTING        ticks         TYPE string        offset        TYPE string OPTIONAL        typekind      TYPE abap_typekind      RETURNING        VALUE(r_data) TYPE string .   PRIVATE SECTION.     DATA mv_extended TYPE bool .    CLASS-DATA mc_me_type TYPE string .    CLASS-DATA mc_cov_error TYPE c . ENDCLASS. *----------------------------------------------------------------------**       CLASS zcl_json MACROS*----------------------------------------------------------------------* DEFINE escape_json_inplace.*  replace all occurrences of regex `[\\"]` in &1 with `\\$0`. <-- this is slower than 2 plain replaces  REPLACE 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 &4        EXPORTING          input    = &1        IMPORTING          output   = &3        EXCEPTIONS          OTHERS   = 1.      IF sy-subrc IS INITIAL.        CONCATENATE `"` &3 `"` INTO &3.      ENDIF.    CATCH cx_root.                                      "#EC NO_HANDLER    ENDTRY.  ELSE.    CASE &2->type_kind.      WHEN cl_abap_typedescr=>typekind_float OR cl_abap_typedescr=>typekind_int OR cl_abap_typedescr=>typekind_int1 OR           cl_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 beginning              SHIFT &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 NOTEXT          ELSEIF mc_bool_3state CS &2->absolute_name AND &1 IS INITIAL.            &3 = `null`.                                    "#EC NOTEXT          ELSE.            &3 = `false`.                                   "#EC NOTEXT          ENDIF.        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 NOTEXT        ELSE.          &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 . "#EC WARNOK      IF sy-subrc IS INITIAL.        &3 = -json.      ELSE.        &3 = &1.        TRANSLATE &3 TO LOWER CASE.                       "#EC SYNTCHAR      ENDIF.    WHEN pretty_mode-user.      READ TABLE mt_name_mappings WITH TABLE KEY abap = &1 ASSIGNING . "#EC WARNOK      IF sy-subrc IS INITIAL.        &3 = -json.      ELSE.        &3 = &1.      ENDIF.    WHEN pretty_mode-low_case.      &3 = &1.      TRANSLATE &3 TO LOWER CASE.                         "#EC SYNTCHAR    WHEN 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.02  WHILE 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 further      WHILE 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 data    IF 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 NOTEXT  match = offset - mark.  &1 = json+mark(match).END-OF-DEFINITION.DEFINE eat_bool.  mark   = offset.  while_offset_cs `aeflnrstu`.                              "#EC NOTEXT  match = offset - mark.  IF json+mark(match) EQ `true`.                            "#EC NOTEXT    &1 = c_bool-true.  ELSEIF json+mark(match) EQ `false`.                       "#EC NOTEXT    IF 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 NOTEXT    CLEAR &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.CLASS zcl_json IMPLEMENTATION.  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 _bool      rv_tribool = c_tribool-undefined.    ELSE.      rv_tribool = c_tribool-false.    ENDIF.  ENDMETHOD.                    "bool_to_tribool  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  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 unique    INSERT 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.  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_json        EXPORTING          pretty_name      = pretty_name          name_mappings    = name_mappings          assoc_arrays     = assoc_arrays          conversion_exits = conversion_exits          assoc_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_HANDLER      ENDTRY.    ENDIF.  ENDMETHOD.                    "deserialize  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 signs      length = 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   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:    TYPE any,                     TYPE any,                      TYPE data,                       TYPE LINE OF abap_keydescr_tab,                    LIKE LINE OF lt_symbols,                     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 NOTEXT        ELSEIF 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 .          r_json = dump_int( 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 
. " optimization for structured tables IF lo_typedesc->kind EQ cl_abap_typedescr=>kind_struct. lo_structdesc ?= lo_typedesc. CREATE DATA lo_data_ref LIKE LINE OF
. ASSIGN lo_data_ref->* TO . 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 array IF 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 . READ TABLE lt_symbols WITH KEY name = -name ASSIGNING . APPEND 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 tables IF mv_assoc_arrays_opt EQ abap_true AND lines( lt_symbols ) EQ 1. lv_array_opt = abap_true. ENDIF. ENDIF. LOOP AT
INTO . CLEAR: lt_fields, lv_prop_name. LOOP AT lt_symbols ASSIGNING . ASSIGN -value->* TO . IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. IF -type->kind EQ cl_abap_typedescr=>kind_elem. lo_elem_descr ?= -type. dump_type lo_elem_descr lv_itemval -convexit_out. ELSE. lv_itemval = dump_int( data = type_descr = -type convexit = -convexit_out ). ENDIF. IF lv_array_opt EQ abap_false. CONCATENATE -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 . ASSIGN -value->* TO . lv_keyval = . 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 . ASSIGN -value->* TO . lv_keyval = . 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
INTO . CLEAR lt_fields. LOOP AT lt_symbols ASSIGNING . ASSIGN -value->* TO . IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. IF -type->kind EQ cl_abap_typedescr=>kind_elem. lo_elem_descr ?= -type. dump_type lo_elem_descr lv_itemval -convexit_out. ELSE. lv_itemval = dump_int( data = type_descr = -type convexit = -convexit_out ). ENDIF. CONCATENATE -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
ASSIGNING . lv_itemval = dump_int( data = 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 METHOD dump_symbols. DATA: lv_properties TYPE STANDARD TABLE OF string, lv_itemval TYPE string. FIELD-SYMBOLS: TYPE any, LIKE LINE OF it_symbols. LOOP AT it_symbols ASSIGNING . ASSIGN -value->* TO . IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. lv_itemval = dump_int( data = type_descr = -type convexit = -convexit_out ). CONCATENATE -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. METHOD dump_type. CONSTANTS: lc_typekind_utclong TYPE abap_typekind VALUE "p", " CL_ABAP_TYPEDESCR=>TYPEKIND_UTCLONG -> "p" only from 7.60 lc_typekind_int8 TYPE abap_typekind VALUE "8". " TYPEKIND_INT8 -> "8" only from 7.40 IF convexit IS NOT INITIAL AND data IS NOT INITIAL. TRY. CALL FUNCTION convexit EXPORTING input = data IMPORTING output = r_json EXCEPTIONS OTHERS = 1. IF sy-subrc IS INITIAL. CONCATENATE `"` r_json `"` INTO r_json. ENDIF. CATCH cx_root. "#EC NO_HANDLER ENDTRY. ELSE. CASE type_descr->type_kind. WHEN cl_abap_typedescr=>typekind_float OR cl_abap_typedescr=>typekind_int OR cl_abap_typedescr=>typekind_int1 OR cl_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 beginning SHIFT 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 NOTEXT ELSEIF mc_bool_3state CS type_descr->absolute_name AND data IS INITIAL. r_json = `null`. "#EC NOTEXT ELSE. r_json = `false`. "#EC NOTEXT ENDIF. 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_enum r_json = data. CONCATENATE `"` r_json `"` INTO r_json. WHEN OTHERS. IF data IS INITIAL. r_json = `null`. "#EC NOTEXT ELSE. r_json = data. ENDIF. ENDCASE. ENDIF. ENDMETHOD. "dump_type 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 seconds lv_subsec = lv_ticks MOD 1000. " in subsec IF 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 minutes IF 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. METHOD escape. out = in. REPLACE ALL OCCURRENCES OF `\` IN out WITH `\\`. REPLACE ALL OCCURRENCES OF `"` IN out WITH `\"`. ENDMETHOD. "escape METHOD generate. DATA: lo_json TYPE REF TO zcl_json, offset TYPE i, length TYPE i, lv_json LIKE json. " skip leading BOM signs length = strlen( json ). while_offset_not_cs `"{[` json. lv_json = json+offset. length = length - offset. CREATE OBJECT lo_json EXPORTING pretty_name = pretty_name name_mappings = name_mappings assoc_arrays = c_bool-true assoc_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_HANDLER ENDTRY. ENDMETHOD. 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: TYPE any, TYPE any, LIKE LINE OF lt_json, LIKE LINE OF lt_fields,
TYPE STANDARD TABLE, 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 structure restore_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 . READ TABLE mt_name_mappings_ex WITH TABLE KEY json = -name ASSIGNING . IF sy-subrc IS INITIAL. ls_comp-name = -abap. ELSE. cache-json = ls_comp-name = -name. " remove characters not allowed in component names TRANSLATE ls_comp-name USING mc_name_symbols_map. 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 NOTEXT ENDIF. TRANSLATE ls_comp-name TO UPPER CASE. cache-abap = ls_comp-name = lv_comp_name = ls_comp-name. " truncate by allowed field name length INSERT 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 . LOOP AT lt_fields ASSIGNING . ASSIGN COMPONENT sy-tabix OF STRUCTURE TO . = generate_int( -value ). ENDLOOP. CATCH cx_sy_create_data_error cx_sy_struct_creation. "#EC NO_HANDLER ENDTRY. ENDIF. RETURN. WHEN `[`."result must be a table of ref restore_type( EXPORTING json = json length = length CHANGING data = lt_json ). CREATE DATA rr_data TYPE ref_tab. ASSIGN rr_data->* TO
. LOOP AT lt_json ASSIGNING . APPEND INITIAL LINE TO
ASSIGNING . = generate_int( ). ENDLOOP. RETURN. WHEN `"`."string CREATE 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`. " number IF 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 NOTEXT CREATE DATA rr_data TYPE abap_bool. ENDIF. ENDCASE. IF rr_data IS BOUND. ASSIGN rr_data->* TO . restore_type( EXPORTING json = json length = length CHANGING data = ). ENDIF. ENDMETHOD. 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. METHOD get_convexit_func. DATA: ls_dfies TYPE dfies. elem_descr->get_ddic_field( RECEIVING p_flddescr = ls_dfies " Field Description EXCEPTIONS not_found = 1 no_ddic_type = 2 OTHERS = 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. METHOD get_fields. DATA: lt_symbols TYPE t_t_symbol, lv_name TYPE char128, ls_field LIKE LINE OF rt_fields. FIELD-SYMBOLS: LIKE LINE OF lt_symbols, 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 WHERE read_only EQ abap_false. MOVE-CORRESPONDING TO ls_field. " insert as UPPER CASE INSERT 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 printed IF mv_pretty_name NE pretty_mode-none AND mv_pretty_name NE pretty_mode-low_case. format_name -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 logic lv_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. 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: LIKE LINE OF comp_tab, LIKE LINE OF cl_abap_objectdescr=>attributes, LIKE LINE OF mt_name_mappings, 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 . IF -name IS NOT INITIAL AND ( -as_include EQ abap_false OR include_aliases EQ abap_true OR mv_expand_includes EQ abap_false ). symb-name = -name. symb-type = -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 . GET REFERENCE OF 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 -as_include EQ abap_true AND mv_expand_includes EQ abap_true. struct_descr ?= -type. symb_tab = get_symbols( type_descr = struct_descr include_aliases = include_aliases ). LOOP AT symb_tab INTO symb. CONCATENATE symb-name -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 . GET REFERENCE OF 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 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->(-name) TO . CHECK sy-subrc IS INITIAL. " we can only assign to public attributes symb-name = -name. symb-read_only = -is_read_only. symb-type = class_descr->get_attribute_type( -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 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 METHOD is_compressable. rv_compress = abap_true. ENDMETHOD. METHOD pretty_name. DATA: tokens TYPE TABLE OF char128, cache LIKE LINE OF mt_name_mappings. FIELD-SYMBOLS: LIKE LINE OF tokens, LIKE LINE OF mt_name_mappings. READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING . IF sy-subrc IS INITIAL. out = -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 FROM 2. TRANSLATE (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 METHOD pretty_name_ex. DATA: tokens TYPE TABLE OF char128, cache LIKE LINE OF mt_name_mappings. FIELD-SYMBOLS: LIKE LINE OF tokens, LIKE LINE OF mt_name_mappings. READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING . IF sy-subrc IS INITIAL. out = -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 FROM 2. TRANSLATE (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 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: TYPE any, LIKE LINE OF field_cache. 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 protected CREATE 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 . fields = get_fields( type_descr = type_descr data = data_ref ). restore( EXPORTING json = json length = length type_descr = type_descr field_cache = fields CHANGING data = 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 . IF sy-subrc IS NOT INITIAL. TRANSLATE name_json TO UPPER CASE. READ TABLE fields WITH TABLE KEY name = name_json ASSIGNING . ENDIF. IF sy-subrc IS INITIAL. ASSIGN -value->* TO . restore_type( EXPORTING json = json length = length type_descr = -type convexit = -convexit_in CHANGING data = 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 METHOD restore_type. DATA: mark LIKE offset, match LIKE offset, sdummy TYPE string, "#EC NEEDED rdummy TYPE REF TO data, "#EC NEEDED pos 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: TYPE any, TYPE any, TYPE data, LIKE LINE OF lt_fields,
TYPE ANY TABLE, 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 deserialization mark = offset. restore_type( EXPORTING json = json length = length CHANGING offset = offset ). match = offset - mark. data = json+mark(match). ENDIF. CASE json+offset(1). WHEN `{`. " object IF 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
. CLEAR
. CREATE DATA line LIKE LINE OF
. ASSIGN line->* TO . 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 . key_ref = -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 . ENDIF. ENDIF. ENDIF. eat_white. WHILE offset < length AND json+offset(1) NE `}`. CLEAR . eat_name key_value. eat_white. eat_char `:`. eat_white. IF IS ASSIGNED. ASSIGN -value->* TO . restore_type( EXPORTING json = json length = length type_descr = -type convexit = -convexit_in CHANGING data = offset = offset ). ELSE. restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fields CHANGING data = offset = offset ). ENDIF. IF table_descr->key_defkind EQ table_descr->keydefkind_user. IF key_ref IS BOUND. ASSIGN key_ref->* TO . IF IS INITIAL. = key_value. ENDIF. ENDIF. ELSEIF IS INITIAL. = key_value. ENDIF. INSERT INTO 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 . restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING data = offset = offset ). ENDIF. ELSE. restore( EXPORTING json = json length = length type_descr = type_descr field_cache = field_cache CHANGING data = data offset = offset ). ENDIF. ELSE. restore( EXPORTING json = json length = length CHANGING offset = offset ). ENDIF. WHEN `[`. " array IF 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 . restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING 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
. CLEAR
. CREATE DATA line LIKE LINE OF
. ASSIGN line->* TO . lt_fields = get_fields( type_descr = data_descr data = line ). WHILE offset < length AND json+offset(1) NE `]`. CLEAR . restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fields CHANGING data = offset = offset ). INSERT INTO TABLE
. eat_white. IF offset < length AND json+offset(1) NE `]`. eat_char `,`. eat_white. ELSE. EXIT. ENDIF. ENDWHILE. ELSE. " skip array eat_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 `"`. " string eat_string sdummy. IF type_descr IS NOT INITIAL. " unescape string IF 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_convexit EXPORTING input = sdummy IMPORTING output = data EXCEPTIONS error_message = 2 OTHERS = 1. IF sy-subrc IS INITIAL. RETURN. ENDIF. CATCH cx_root. "#EC NO_HANDLER ENDTRY. 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.Guid REPLACE 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 sdummy WITH `$1$2$3$4$5` REPLACEMENT LENGTH match IGNORING CASE. "#EC NOTEXT IF sy-subrc EQ 0. sdummy = sdummy(match). TRANSLATE sdummy TO UPPER CASE. data = sdummy. 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_8601 REPLACE FIRST OCCURRENCE OF REGEX `^(\d{4})-(\d{2})-(\d{2})` IN sdummy WITH `$1$2$3` REPLACEMENT LENGTH match. "#EC NOTEXT IF 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 NOTEXT IF 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-durationRep REPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$1$2$3` REPLACEMENT LENGTH match. "#EC NOTEXT IF 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_8601 REPLACE FIRST OCCURRENCE OF REGEX `^(\d{2}):(\d{2}):(\d{2})` IN sdummy WITH `$1$2$3` REPLACEMENT LENGTH match. "#EC NOTEXT IF 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 NOTEXT IF 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-durationRep REPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$4$5$6` REPLACEMENT LENGTH match. "#EC NOTEXT IF 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 NOTEXT IF 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 NOTEXT IF 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-durationRep REPLACE FIRST OCCURRENCE OF REGEX `^-?P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)(?:\.(\d+))?S)?)?` IN sdummy WITH `$1$2$3$4$5$6.$7` REPLACEMENT LENGTH match. "#EC NOTEXT IF sy-subrc EQ 0. sdummy = sdummy(match). ENDIF. ENDIF. ENDIF. WHEN `k`. "cl_abap_typedescr=>typekind_enum TRY. CALL METHOD ("CL_ABAP_XSD")=>("TO_VALUE") EXPORTING cs = sdummy CHANGING val = data. RETURN. CATCH cx_sy_dyn_call_error. throw_error. " Deserialization of enums is not supported ENDTRY. ENDCASE. ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. CREATE DATA rdummy TYPE string. ASSIGN rdummy->* TO . = sdummy. data ?= rdummy. RETURN. ELSE. throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTED ENDIF. data = sdummy. ELSEIF type_descr->kind EQ cl_abap_typedescr=>kind_elem. CLEAR data. ELSE. throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTED ENDIF. ENDIF. WHEN `-` OR `0` OR `1` OR `2` OR `3` OR `4` OR `5` OR `6` OR `7` OR `8` OR `9`. " number IF 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 NOTEXT match = strlen( sdummy ). IF sdummy CS ".". " float. CREATE DATA rdummy TYPE f. ELSEIF match GT 9. " packed CREATE DATA rdummy TYPE p. ELSE. " integer CREATE DATA rdummy TYPE i. ENDIF. ASSIGN rdummy->* TO . = sdummy. data ?= rdummy. ELSEIF type_descr->kind EQ type_descr->kind_elem. IF lv_convexit IS NOT INITIAL. TRY . eat_number sdummy. "#EC NOTEXT CALL FUNCTION lv_convexit EXPORTING input = sdummy IMPORTING output = data EXCEPTIONS error_message = 2 OTHERS = 1. IF sy-subrc IS INITIAL. RETURN. ENDIF. CATCH cx_root. "#EC NO_HANDLER ENDTRY. ENDIF. eat_number data. "#EC NOTEXT ELSE. eat_number sdummy. "#EC NOTEXT throw_error. ENDIF. ELSE. eat_number sdummy. "#EC NOTEXT ENDIF. WHEN OTHERS. " boolean, e.g true/false/null IF 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 . eat_bool . "#EC NOTEXT data ?= rdummy. ELSEIF type_descr->kind EQ type_descr->kind_elem. eat_bool data. "#EC NOTEXT ELSE. eat_bool sdummy. "#EC NOTEXT throw_error. ENDIF. ELSE. eat_bool sdummy. "#EC NOTEXT ENDIF. 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_error EXPORTING previous = lo_exp. ENDIF. ENDTRY. ENDMETHOD. "restore_type 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_json EXPORTING compress = compress pretty_name = pretty_name name_mappings = name_mappings assoc_arrays = assoc_arrays assoc_arrays_opt = assoc_arrays_opt expand_includes = expand_includes numc_as_string = numc_as_string conversion_exits = conversion_exits ts_as_iso8601 = ts_as_iso8601. r_json = lo_json->serialize_int( name = name data = data type_descr = type_descr ). ENDMETHOD. "serialize 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 harm REPLACE 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`. 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 METHOD string_to_raw. CALL FUNCTION "SCMS_STRING_TO_XSTRING" EXPORTING text = iv_string encoding = iv_encoding IMPORTING buffer = rv_xstring EXCEPTIONS OTHERS = 1. IF sy-subrc IS NOT INITIAL. CLEAR rv_xstring. ENDIF. ENDMETHOD. METHOD raw_to_string. DATA: lv_output_length TYPE i, lt_binary_tab TYPE STANDARD TABLE OF sdokcntbin. CALL FUNCTION "SCMS_XSTRING_TO_BINARY" EXPORTING buffer = iv_xstring IMPORTING output_length = lv_output_length TABLES binary_tab = lt_binary_tab. CALL FUNCTION "SCMS_BINARY_TO_STRING" EXPORTING input_length = lv_output_length encoding = iv_encoding IMPORTING text_buffer = rv_string output_length = lv_output_length TABLES binary_tab = lt_binary_tab. ENDMETHOD. METHOD string_to_xstring. DATA: lv_xstring TYPE xstring. CALL FUNCTION "SSFC_BASE64_DECODE" EXPORTING b64data = in IMPORTING bindata = lv_xstring EXCEPTIONS OTHERS = 1. IF sy-subrc IS INITIAL. out = lv_xstring. ELSE. out = in. ENDIF. ENDMETHOD. "string_to_xstring METHOD xstring_to_string. DATA: lv_xstring TYPE xstring. " let us fix data conversion issues here lv_xstring = in. CALL FUNCTION "SSFC_BASE64_ENCODE" EXPORTING bindata = lv_xstring IMPORTING b64data = out EXCEPTIONS OTHERS = 1. IF sy-subrc IS NOT INITIAL. out = in. ENDIF. ENDMETHOD. "xstring_to_string 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_undefined ENDIF. ENDMETHOD. "TRIBOOL_TO_BOOL 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: LIKE LINE OF lt_matches. " see reference for escaping rules in JSON RFC " https://www.ietf.org/rfc/rfc4627.txt unescaped = 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 . lv_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 \\, \", \/ etc REPLACE ALL OCCURRENCES OF REGEX `\\(.)` IN unescaped WITH `$1` RESPECTING CASE. ENDMETHOD.ENDCLASS.

然后输入事务代码se38,左上角对象类型->导入->程序中的局部类输入程序名,记得激活源程序,否则不会显示类左边是源程序里的,右边是要新建的类名,重命名一下,我命名的是ZCL_JSON,记得要Z开头,否则系统判定是要建立系统类,需要输入键值。导入后还不能直接用,因为他这个不会导入宏定义,需要手动导入,宏定义的代码如下:

DEFINE ESCAPE_JSON_INPLACE.*  replace all occurrences of regex `[\\"]` in &1 with `\\$0`. <-- this is slower than 2 plain replaces  REPLACE 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 &4      EXPORTING        INPUT    = &1      IMPORTING        OUTPUT   = &3      EXCEPTIONS        OTHERS   = 1.      IF SY-SUBRC IS INITIAL.        CONCATENATE `"` &3 `"` INTO &3.      ENDIF.    CATCH CX_ROOT.                                    "#EC NO_HANDLER    ENDTRY.  ELSE.    CASE &2->TYPE_KIND.    WHEN CL_ABAP_TYPEDESCR=>TYPEKIND_FLOAT OR CL_ABAP_TYPEDESCR=>TYPEKIND_INT OR CL_ABAP_TYPEDESCR=>TYPEKIND_INT1 OR      CL_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 beginning            SHIFT &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 NOTEXT      ELSEIF MC_BOOL_3STATE CS &2->ABSOLUTE_NAME AND &1 IS INITIAL.          &3 = `null`.                                    "#EC NOTEXT        ELSE.          &3 = `false`.                                   "#EC NOTEXT        ENDIF.      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 NOTEXT      ELSE.        &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 . "#EC WARNOK    IF SY-SUBRC IS INITIAL.      &3 = -JSON.    ELSE.      &3 = &1.      TRANSLATE &3 TO LOWER CASE.                       "#EC SYNTCHAR    ENDIF.  WHEN PRETTY_MODE-USER.    READ TABLE MT_NAME_MAPPINGS WITH TABLE KEY ABAP = &1 ASSIGNING . "#EC WARNOK    IF SY-SUBRC IS INITIAL.      &3 = -JSON.    ELSE.      &3 = &1.    ENDIF.  WHEN PRETTY_MODE-LOW_CASE.    &3 = &1.    TRANSLATE &3 TO LOWER CASE.                         "#EC SYNTCHAR  WHEN 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.02  WHILE 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 further      WHILE 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 data    IF 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 NOTEXT  MATCH = OFFSET - MARK.  &1 = JSON+MARK(MATCH).END-OF-DEFINITION.DEFINE EAT_BOOL.  MARK   = OFFSET.  WHILE_OFFSET_CS `aeflnrstu`.                              "#EC NOTEXT  MATCH = OFFSET - MARK.  IF JSON+MARK(MATCH) EQ `true`.                            "#EC NOTEXT    &1 = C_BOOL-TRUE.ELSEIF JSON+MARK(MATCH) EQ `false`.                       "#EC NOTEXT    IF 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 NOTEXT    CLEAR &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.

激活后就可以使用了。当然如果你会用abapgit的话,你只需要在github上将JSON2ABAPType下载下来就行了,JSON2ABAPType自带UI2类。这里推荐参考一篇文章ABAP abapgit的使用教程以及ZJSON2ABAPTYPE工具 (JSON转abap代码),JSON2ABAPType程序里一堆新语法,像我这样老版本的sap自然使用不了了,也没精力去改代码了。这里在说一下ui2类的使用技巧,我个人还是挺喜欢CALL TRANSFORMATION id解析json数据的方式的,因为现在经常用到的json格式是这样的

{    "IT_ITEM": [        {            "ZNO": "",            "POSNR": "",            "MATNR": "",            "MENGE": "",            "MEINS": "",            "EINDT":"",            "UMSON": "",            "EBELP": "",            "POSNR_VL": "",            "POSNR_VF": "",            "MAKTX": "",            "SERNP": "",            "GERNR": ""        }    ],    "IT_GERNR": [    ],    "IT_LTEXT": [    ],    "CS_HEAD": {        "ZNO": "",        "BSART": "",        "MWSKZ": "",        "EKORG": "",        "EKGRP": "",        "UMWRK": "",        "UMLGO": "",        "WERKS": "",        "LGORT": "",        "BWART": "",        "BKTXT": "",        "EBELN": "",        "VBELN_VL": "",        "VBELN_VF": "",        "MBLNR": "",        "MJAHR": "",        "BUKRS": "",        "LIFNR": "",        "RETPO": "",        "STATUS": "",        "ZZMSG": "",        "CRUSR": "",        "CRDAT": "",        "CRTIM": "",        "CHUSR": "",        "CHDAT": "",        "CHTIM": "",        "C_SEL": "",        "ICON": "",        "OPER01": "",        "OPER02": "",        "STATUS_TXT": "",        "CRUSR_TXT": "",        "CHUSR_TXT": "",        "EKORG_TXT": "",        "EKGRP_TXT": "",        "WERKS_TXT": "",        "UMWRK_TXT": "",        "LGORT_TXT": "",        "UMLGO_TXT": "",        "ERROR": "",        "REMARK": ""    }}

一个键值代表一个表数据,如果让CALL TRANSFORMATION ID来做的话就是这样

DATA: GT_8101  TYPE TABLE OF ZMMT001D       ,        GT_8200  TYPE TABLE OF ZMMS_STO_ITEM  ,        GT_GERNR TYPE TABLE OF ZMMS_STO_GERNR ,        GS_HEAD  TYPE ZMMS_STO_HEAD.    TRY.        CALL TRANSFORMATION ID        SOURCE XML LV_JSON        RESULT        CS_HEAD = GS_HEAD        IT_LTEXT = GT_8101        IT_ITEM = GT_8200        IT_GERNR = GT_GERNR.      CATCH CX_TRANSFORMATION_ERROR INTO ERROR.        ERR_TEXT = ERROR->GET_TEXT( ).        LV_STATUS = "500".        LV_MESSAGE = ERR_TEXT.    ENDTRY.

LV_JSON是要解析的json数据,注意表结构要和json里的结果完全一致。如果要用ui2来达到CALL TRANSFORMATION ID的效果,则要这样做

DATA: BEGIN OF LS_JSON,        IT_LTEXT  TYPE TABLE OF ZMMT001D       ,        IT_ITEM  TYPE TABLE OF ZMMS_STO_ITEM  ,        IT_GERNR TYPE TABLE OF ZMMS_STO_GERNR ,        CS_HEAD  TYPE ZMMS_STO_HEAD,END OF LS_JSON.    DATA: GT_8101  TYPE TABLE OF ZMMT001D       ,        GT_8200  TYPE TABLE OF ZMMS_STO_ITEM  ,        GT_GERNR TYPE TABLE OF ZMMS_STO_GERNR ,        GS_HEAD  TYPE ZMMS_STO_HEAD.        ZCL_JSON=>DESERIALIZE( EXPORTING JSON = LV_JSON      PRETTY_NAME = ZCL_JSON=>PRETTY_MODE-CAMEL_CASE    CHANGING DATA = LS_JSON ).    IF LS_JSON-IT_LTEXT IS NOT INITIAL.      GT_8101[] = LS_JSON-IT_LTEXT.    ENDIF.    IF LS_JSON-IT_GERNR IS NOT INITIAL.      GT_GERNR[] = LS_JSON-IT_GERNR.    ENDIF.    IF LS_JSON-IT_ITEM IS NOT INITIAL.      GT_8200[] = LS_JSON-IT_ITEM.    ENDIF.    IF LS_JSON-CS_HEAD IS NOT INITIAL.      GS_HEAD = LS_JSON-CS_HEAD.    ENDIF.

先把数据解析到结构体里,再分别将表数据赋值给定义好的表。

关键词: 因为现在 程序中的 终于找到