ABAP Json和对象的转换

news2024/11/24 12:44:05

se24新建类ZCL_JSON保存

点击修改,进入下图界面,点击红框。

复制粘贴下面代码

CLASS zcl_json DEFINITION
  PUBLIC
  CREATE 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 NOTEXT
    CONSTANTS 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.
*"* 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 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.
*"* 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 _bool
      rv_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 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.                    "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_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


* <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 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_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 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 <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 tables
        IF 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 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 <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 tables
              IF 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.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


* <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 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.                    "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 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.                    "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 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 <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 names
              TRANSLATE 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 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 <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_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 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 `"`."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 <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(
      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.                    "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 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 <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 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.                    "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 attributes
        symb-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'
      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.                    "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 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 <value>.
        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 = <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 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: <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 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 <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_in
                                      CHANGING data = <value> offset = offset ).
                      ELSE.
                        restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fields
                                      CHANGING 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_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 <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_fields
                                  CHANGING 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 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. "#EC NOTEXT
                      IF 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_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 <data>.
                  <data> = 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 <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 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 <data>.
                eat_bool <data>.                            "#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


* <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_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


* <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 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`.
* 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'
      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.                    "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'
      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


* <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_undefined
    ENDIF.
  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.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 <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 \\, \", \/ etc
    REPLACE 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 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
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 classes

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 <cache>. "#EC WARNOK
      if sy-subrc is initial.
        &3 = <cache>-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 <cache>. "#EC WARNOK
      if sy-subrc is initial.
        &3 = <cache>-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.02

END-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.

激活,至此完成。

可用下面代码测试。

REPORT zrtest2
       NO 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=>serialize
      EXPORTING
        data           = ls_data
        "pretty_name    = iv_pretty_name
        numc_as_string = 'X'
      RECEIVING
        r_json         = lv_json_str.

CALL METHOD zcl_json=>deserialize
      EXPORTING
        json = lv_json_str
      CHANGING
        data = ls_data2.


if sy-subrc = 0.

endif.

测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1178422.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

效率至少提高2倍!最实用的Linux命令合集

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

上门预约按摩家政小程序开发;

上门预约按摩家政小程序开发&#xff0c;都可以做 上门按摩&#xff0c;服务预约小程序开发 服务预约类小程序开发。 小程序开放订单预约、即时服务、在线评价用户管理、会员充值、平优惠券、、平台自营、抢单、事个人入驻、分销邀请、商户入驻 等等 按摩上门预约、回收上门预约…

CSS默认宽度

所谓的默认宽度&#xff0c;就是不设置width属性时&#xff0c;元素所呈现出来的宽度 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title></title><style>* {margin: 0;padding: 0;}.box {/…

【数据结构】——顺序表(增删查改)

目录 前言&#xff1a; 顺序表&#xff1a; 1、概念及分类 1.1顺序表分类 静态顺序表 动态顺序表 2、接口实现 2.1功能要求 2.2功能实现 &#x1f4a1;初始化顺序表 &#x1f4a1;销毁顺序表 &#x1f4a1;顺序表尾插入 &#x1f4a1;检查是否扩容 &#x1f4a1;…

科技创意赋能乡村文旅振兴

近日&#xff0c;由北京大学创意产业研究中心联合中国国际科技促进会新基建专委会共同主办的“科技创意赋能乡村振兴研讨会”在京举行&#xff0c;与会专家学者围绕“和美乡村共同富裕智慧文旅”主题进行深入探讨。北京大学创意产业研究中心副主任吕艺、国家文化和旅游公共服务…

Python点云处理(十九)点云地面点提取——CSF布料模拟算法

目录 0 简述1 算法原理2 具体步骤3 实现0 简述 对于点云地面点滤波,众多传统算法滤波效果容易受到地形特征的影响(通常在复杂场景及陡峭地形区域滤波效果较差)且常常需要用户对数据有较为丰富的先验知识来进行设置滤波器中的各种参数。为了解决这些问题,张吴明教授等人提出…

Allegro如何快速将目标旋转90度操作指导

Allegro如何快速将目标旋转90度操作指导 在用Allegro进行PCB设计的时候,时常需要目标旋转90度,我们常用的命令是Spin,如下图以旋转电阻为例 点击Edit点击SpinOp

数据结构初阶---复杂度的OJ例题

复杂度的OJ例题 一、消失的数字1.思路一2.思路二3.思路三 二、旋转数组1.思路一2.思路二3.思路三 一、消失的数字 数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(N)时间内完成吗&#xff1f; 链接&#xff1a;力扣&…

用「埋点」记录自己,不妄过一生

最近有朋友问我「埋点怎么做」&#xff0c;给朋友讲了一些互联网广告的案例&#xff0c;从源头的数据采集讲到末尾的应用分析和流量分配等&#xff08;此处省略N多字&#xff09; 解释完以后&#xff0c;我想到一个问题&#xff1a;有了埋点可以做分析&#xff0c;那我们对自己…

尚硅谷大数据项目《在线教育之实时数仓》笔记006

视频地址&#xff1a;尚硅谷大数据项目《在线教育之实时数仓》_哔哩哔哩_bilibili 目录 第9章 数仓开发之DWD层 P041 P042 P043 P044 P045 P046 P047 P048 P049 P050 P051 P052 第9章 数仓开发之DWD层 P041 9.3 流量域用户跳出事务事实表 P042 DwdTrafficUserJum…

Android岗位居然要求有鸿蒙开发的需求了?HarmonyOS它来了

鸿蒙才开发几年,就已经让对手们脊背发凉了&#xff0c;要知道主流操作系统都是积累几十年的产物。 以苹果MacOS为例,其前身NextStep是85年开干的。另一家微软公司,Win95爆卖的时候,中国还没加入WTO。 大家使用过鸿蒙系统产品的,应该能直观感觉到它的流畅性,易用性,如果你有个…

leetcode刷题日记:70.Climbing Stairs(爬楼梯)

给了我们n阶楼梯让我们去爬&#xff0c;每次只能爬1阶或2阶&#xff0c;这个我们可以使用递归的方法进行解决&#xff0c;向上爬的过程与向下降的过程是一样的&#xff0c;所以我们就可以这样考虑&#xff0c;现在就是n阶楼梯每一次下降1阶或2阶有多少种方法刚好下降到0阶。 i…

IDEA取消git对项目的版本控制

前言 前几天新建项目的时候不小心选了个git仓库&#xff0c;导致这个测试项目一直被git管理着。 解决办法 1 右键项目 选择打开资源目录 2 删除.git文件 把目录下的.git文件删掉 3 删除idea中的git管理 删除完.git文件后&#xff0c;进入idea&#xff0c;右下角会有这样的提…

ElementUI-tree拖拽功能与节点自定义

前言 在管理端会遇到多分类时&#xff0c;要求有层次展示出来&#xff0c;并且每个分类有额外的操作。例如&#xff1a;添加分类、编辑分类、删除、拖到分类等。 下面将会记录这样的一个需求实习过程。 了解需求 分类展示按层级展示分类根据特定的参数展示可以操作的按钮&a…

cookie、session和Token的区别?JWT又是什么?单点登录又是什么?头大?快进来看看,一文帮你捋清楚~

目录 0、HTTP是无状态的 1、前端标记cookie 1.1、cookie限制空间范围 1.2、cookie限制时间范围 1.3、cookie限制使用方式 2、服务端存储session库 2.1、我们先来简单聊聊session是什么&#xff1f; 2.2、session的存储方式 2.3、session的过期和销毁 2.4、session的分…

操作系统:文件管理(二)文件系统

一战成硕 4.3 文件系统4.3.1 文件系统结构4.3.2 文件系统布局4.3.3 外存空闲空间管理4.3.4 虚拟文件系统 4.3 文件系统 4.3.1 文件系统结构 4.3.2 文件系统布局 文件系统在磁盘中的结构 文件系统在内存中的结构 内存中的信息用于管理文件系统并通过缓存提高性能&#xff0c;这…

HDFS系统权限详解

一&#xff0c;HDFS超级用户 启动namenode的用户就是HDFS中的超级用户 如图所示 HDFS中&#xff0c;也是有权限控制的&#xff0c;其控制逻辑和Linux文件系统的完全一致 但是不同的是&#xff0c;两个系统的Supergroup不同(超级用户不同) Linux的操作用户是root HDFS文件系统的…

AI 编程界的扛把子

大家好&#xff0c;我是伍六七。 全国最大 AI 社群《AI 破局俱乐部》初创合伙人。8 年 Java 经验&#xff0c;干过开发&#xff0c;也做过管理。目前在某互联网大厂从事 Java 开发&#xff0c;业余时间研究 AI 编程。 我从 2022 年底&#xff0c;ChatGPT 问世&#xff0c;就密…

K8S知识点(五)

&#xff08;1&#xff09;资源管理介绍 Pod控制器的作用&#xff0c;就是为了最终产生各种各样的Pod&#xff0c;Pod里面运行容器&#xff0c;容器里面运行程序 程序需要数据持久化&#xff0c;可以用数据存储卷来存储 Pod想要让外部访问需要通过Service代理&#xff0c;外部…

基于Pytorch框架的LSTM算法(一)——单维度单步预测(1)

1.项目说明 使用data中的close列的时间序列数据完成预测【使用close列数据中的前windowback-1天数据完成未来一天close的预测】 2.数据集 Date,Open,High,Low,Close,Adj Close,Volume 2018-05-23,182.500000,186.910004,182.179993,186.899994,186.899994,16628100 2018-05…