ABAP Json和对象的转换

se24新建类ZCL_JSON保存

ABAP Json和对象的转换_第1张图片

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

ABAP Json和对象的转换_第2张图片

复制粘贴下面代码

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.


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>BOOL_TO_TRIBOOL
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_BOOL                        TYPE        BOOL
* | [<-()] RV_TRIBOOL                     TYPE        TRIBOOL
* +--------------------------------------------------------------------------------------
  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


* ---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_JSON=>CLASS_CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------
  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


* ---------------------------------------------------------------------------------------+
* | 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)
* +--------------------------------------------------------------------------------------
  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


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


* ---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_JSON->DESERIALIZE_INT
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON                           TYPE        JSON(optional)
* | [--->] JSONX                          TYPE        XSTRING(optional)
* | [<-->] DATA                           TYPE        DATA
* | [!CX!] CX_SY_MOVE_CAST_ERROR
* +--------------------------------------------------------------------------------------
  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


* ---------------------------------------------------------------------------------------+
* | 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
* +--------------------------------------------------------------------------------------
  METHOD dump_int.
    DATA: lo_typedesc   TYPE REF TO cl_abap_typedescr,
       lo_elem_descr TYPE REF TO cl_abap_elemdescr,
       lo_classdesc  TYPE REF TO cl_abap_classdescr,
       lo_structdesc TYPE REF TO cl_abap_structdescr,
       lo_tabledescr TYPE REF TO cl_abap_tabledescr,
       lt_symbols    TYPE t_t_symbol,
       lt_keys       LIKE lt_symbols,
       lt_properties TYPE STANDARD TABLE OF string,
       lt_fields     TYPE STANDARD TABLE OF string,
       lo_obj_ref    TYPE REF TO object,
       lo_data_ref   TYPE REF TO data,
       ls_skip_key   TYPE LINE OF abap_keydescr_tab,
       lv_array_opt  TYPE abap_bool,
       lv_prop_name  TYPE string,
       lv_keyval     TYPE string,
       lv_itemval    TYPE string.

    FIELD-SYMBOLS:    TYPE any,
                     TYPE any,
                      TYPE data,
                       TYPE LINE OF abap_keydescr_tab,
                    LIKE LINE OF lt_symbols,
                     TYPE ANY TABLE.

    " we need here macro instead of method calls because of the performance reasons.
    " based on SAT measurements.

    CASE type_descr->kind.
      WHEN cl_abap_typedescr=>kind_ref.

        IF data IS INITIAL.
          r_json = `null`.                                  "#EC NOTEXT
        ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref.
          lo_data_ref ?= data.
          lo_typedesc = cl_abap_typedescr=>describe_by_data_ref( lo_data_ref ).
          ASSIGN lo_data_ref->* TO .
          r_json = dump_int( data =  type_descr = lo_typedesc ).
        ELSE.
          lo_obj_ref ?= data.
          lo_classdesc ?= cl_abap_typedescr=>describe_by_object_ref( lo_obj_ref ).
          lt_symbols = get_symbols( type_descr = lo_classdesc object = lo_obj_ref ).
          r_json = dump_symbols( lt_symbols ).
        ENDIF.

      WHEN cl_abap_typedescr=>kind_elem.
        lo_elem_descr ?= type_descr.
        dump_type data lo_elem_descr r_json convexit.

      WHEN cl_abap_typedescr=>kind_struct.

        lo_structdesc ?= type_descr.
        GET REFERENCE OF data INTO lo_data_ref.
        lt_symbols = get_symbols( type_descr = lo_structdesc data = lo_data_ref ).
        r_json = dump_symbols( lt_symbols ).

      WHEN cl_abap_typedescr=>kind_table.

        lo_tabledescr ?= type_descr.
        lo_typedesc = lo_tabledescr->get_table_line_type( ).

        ASSIGN data TO 
. " optimization for structured tables IF lo_typedesc->kind EQ cl_abap_typedescr=>kind_struct. lo_structdesc ?= lo_typedesc. CREATE DATA lo_data_ref LIKE LINE OF
. ASSIGN lo_data_ref->* TO . lt_symbols = get_symbols( type_descr = lo_structdesc data = lo_data_ref ). " here we have differentiation of output of simple table to JSON array " and sorted or hashed table with unique key into JSON associative array IF lo_tabledescr->has_unique_key IS NOT INITIAL AND mv_assoc_arrays IS NOT INITIAL. IF lo_tabledescr->key_defkind EQ lo_tabledescr->keydefkind_user. LOOP AT lo_tabledescr->key ASSIGNING . READ TABLE lt_symbols WITH KEY name = -name ASSIGNING . APPEND TO lt_keys. ENDLOOP. ENDIF. IF lines( lo_tabledescr->key ) EQ 1. READ TABLE lo_tabledescr->key INDEX 1 INTO ls_skip_key. DELETE lt_symbols WHERE name EQ ls_skip_key-name. " remove object wrapping for simple name-value tables IF mv_assoc_arrays_opt EQ abap_true AND lines( lt_symbols ) EQ 1. lv_array_opt = abap_true. ENDIF. ENDIF. LOOP AT
INTO . CLEAR: lt_fields, lv_prop_name. LOOP AT lt_symbols ASSIGNING . ASSIGN -value->* TO . IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. IF -type->kind EQ cl_abap_typedescr=>kind_elem. lo_elem_descr ?= -type. dump_type lo_elem_descr lv_itemval -convexit_out. ELSE. lv_itemval = dump_int( data = type_descr = -type convexit = -convexit_out ). ENDIF. IF lv_array_opt EQ abap_false. CONCATENATE -header lv_itemval INTO lv_itemval. ENDIF. APPEND lv_itemval TO lt_fields. ENDIF. ENDLOOP. IF lo_tabledescr->key_defkind EQ lo_tabledescr->keydefkind_user. LOOP AT lt_keys ASSIGNING . ASSIGN -value->* TO . lv_keyval = . CONDENSE lv_keyval. IF lv_prop_name IS NOT INITIAL. CONCATENATE lv_prop_name mc_key_separator lv_keyval INTO lv_prop_name. ELSE. lv_prop_name = lv_keyval. ENDIF. ENDLOOP. ELSE. LOOP AT lt_symbols ASSIGNING . ASSIGN -value->* TO . lv_keyval = . CONDENSE lv_keyval. IF lv_prop_name IS NOT INITIAL. CONCATENATE lv_prop_name mc_key_separator lv_keyval INTO lv_prop_name. ELSE. lv_prop_name = lv_keyval. ENDIF. ENDLOOP. ENDIF. CONCATENATE LINES OF lt_fields INTO lv_itemval SEPARATED BY `,`. IF lv_array_opt EQ abap_false. CONCATENATE `"` lv_prop_name `":{` lv_itemval `}` INTO lv_itemval. ELSE. CONCATENATE `"` lv_prop_name `":` lv_itemval `` INTO lv_itemval. ENDIF. APPEND lv_itemval TO lt_properties. ENDLOOP. CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`. CONCATENATE `{` r_json `}` INTO r_json. ELSE. LOOP AT
INTO . CLEAR lt_fields. LOOP AT lt_symbols ASSIGNING . ASSIGN -value->* TO . IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. IF -type->kind EQ cl_abap_typedescr=>kind_elem. lo_elem_descr ?= -type. dump_type lo_elem_descr lv_itemval -convexit_out. ELSE. lv_itemval = dump_int( data = type_descr = -type convexit = -convexit_out ). ENDIF. CONCATENATE -header lv_itemval INTO lv_itemval. APPEND lv_itemval TO lt_fields. ENDIF. ENDLOOP. CONCATENATE LINES OF lt_fields INTO lv_itemval SEPARATED BY `,`. CONCATENATE `{` lv_itemval `}` INTO lv_itemval. APPEND lv_itemval TO lt_properties. ENDLOOP. CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`. CONCATENATE `[` r_json `]` INTO r_json. ENDIF. ELSE. LOOP AT
ASSIGNING . lv_itemval = dump_int( data = type_descr = lo_typedesc ). APPEND lv_itemval TO lt_properties. ENDLOOP. CONCATENATE LINES OF lt_properties INTO r_json SEPARATED BY `,`. CONCATENATE `[` r_json `]` INTO r_json. ENDIF. ENDCASE. ENDMETHOD. "DUMP_INT * ---------------------------------------------------------------------------------------+ * | Instance Protected Method ZCL_JSON->DUMP_SYMBOLS * +-------------------------------------------------------------------------------------------------+ * | [--->] IT_SYMBOLS TYPE T_T_SYMBOL * | [<-()] R_JSON TYPE JSON * +-------------------------------------------------------------------------------------- METHOD dump_symbols. DATA: lv_properties TYPE STANDARD TABLE OF string, lv_itemval TYPE string. FIELD-SYMBOLS: TYPE any, LIKE LINE OF it_symbols. LOOP AT it_symbols ASSIGNING . ASSIGN -value->* TO . IF mv_compress IS INITIAL OR IS NOT INITIAL OR -compressable EQ abap_false. lv_itemval = dump_int( data = type_descr = -type convexit = -convexit_out ). CONCATENATE -header lv_itemval INTO lv_itemval. APPEND lv_itemval TO lv_properties. ENDIF. ENDLOOP. CONCATENATE LINES OF lv_properties INTO r_json SEPARATED BY `,`. CONCATENATE `{` r_json `}` INTO r_json. ENDMETHOD. "DUMP_SYMBOLS * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | Static Protected Method ZCL_JSON=>EDM_DATETIME_TO_TS * +-------------------------------------------------------------------------------------------------+ * | [--->] TICKS TYPE STRING * | [--->] OFFSET TYPE STRING(optional) * | [--->] TYPEKIND TYPE ABAP_TYPEKIND * | [<-()] R_DATA TYPE STRING * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | Static Protected Method ZCL_JSON=>ESCAPE * +-------------------------------------------------------------------------------------------------+ * | [--->] IN TYPE ANY * | [<-()] OUT TYPE STRING * +-------------------------------------------------------------------------------------- METHOD escape. out = in. REPLACE ALL OCCURRENCES OF `\` IN out WITH `\\`. REPLACE ALL OCCURRENCES OF `"` IN out WITH `\"`. ENDMETHOD. "ESCAPE * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- METHOD generate_int. TYPES: BEGIN OF ts_field, name TYPE string, value TYPE json, END OF ts_field. DATA: offset TYPE i. DATA: lt_json TYPE STANDARD TABLE OF json WITH DEFAULT KEY, lv_comp_name TYPE abap_compname, lt_fields TYPE SORTED TABLE OF ts_field WITH UNIQUE KEY name, lo_type TYPE REF TO cl_abap_datadescr, lt_comp TYPE abap_component_tab, lt_names TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line, cache LIKE LINE OF mt_name_mappings_ex, ls_comp LIKE LINE OF lt_comp. FIELD-SYMBOLS: TYPE any, TYPE any, LIKE LINE OF lt_json, LIKE LINE OF lt_fields,
TYPE STANDARD TABLE, LIKE LINE OF mt_name_mappings_ex. IF length IS NOT SUPPLIED. length = strlen( json ). ENDIF. eat_white. CASE json+offset(1). WHEN `{`."result must be a structure restore_type( EXPORTING json = json length = length CHANGING data = lt_fields ). IF lt_fields IS NOT INITIAL. ls_comp-type = cl_abap_refdescr=>get_ref_to_data( ). LOOP AT lt_fields ASSIGNING . READ TABLE mt_name_mappings_ex WITH TABLE KEY json = -name ASSIGNING . IF sy-subrc IS INITIAL. ls_comp-name = -abap. ELSE. cache-json = ls_comp-name = -name. " remove characters not allowed in component names TRANSLATE ls_comp-name USING ` _/_\_:_~_._-_=_>_<_(_)_@_+_*_?_&_$_#_%_^_`. IF mv_pretty_name EQ pretty_mode-camel_case OR mv_pretty_name EQ pretty_mode-extended. REPLACE ALL OCCURRENCES OF REGEX `([a-z])([A-Z])` IN ls_comp-name WITH `$1_$2`. "#EC NOTEXT ENDIF. TRANSLATE ls_comp-name TO UPPER CASE. cache-abap = ls_comp-name = lv_comp_name = ls_comp-name. " truncate by allowed field name length INSERT cache INTO TABLE mt_name_mappings_ex. ENDIF. INSERT ls_comp-name INTO TABLE lt_names. IF sy-subrc IS INITIAL. APPEND ls_comp TO lt_comp. ELSE. DELETE lt_fields. ENDIF. ENDLOOP. TRY. lo_type = cl_abap_structdescr=>create( p_components = lt_comp p_strict = c_bool-false ). CREATE DATA rr_data TYPE HANDLE lo_type. ASSIGN rr_data->* TO . LOOP AT lt_fields ASSIGNING . ASSIGN COMPONENT sy-tabix OF STRUCTURE TO . = generate_int( -value ). ENDLOOP. CATCH cx_sy_create_data_error cx_sy_struct_creation. "#EC NO_HANDLER ENDTRY. ENDIF. RETURN. WHEN `[`."result must be a table of ref restore_type( EXPORTING json = json length = length CHANGING data = lt_json ). CREATE DATA rr_data TYPE TABLE OF REF TO data. ASSIGN rr_data->* TO
. LOOP AT lt_json ASSIGNING . APPEND INITIAL LINE TO
ASSIGNING . = generate_int( ). ENDLOOP. RETURN. WHEN `"`."string CREATE DATA rr_data TYPE string. WHEN `-` OR `0` OR `1` OR `2` OR `3` OR `4` OR `5` OR `6` OR `7` OR `8` OR `9`. " number IF json+offset CS '.'. CREATE DATA rr_data TYPE f. ELSEIF length GT 9. CREATE DATA rr_data TYPE p. ELSE. CREATE DATA rr_data TYPE i. ENDIF. WHEN OTHERS. IF json+offset EQ `true` OR json+offset EQ `false`. "#EC NOTEXT CREATE DATA rr_data TYPE abap_bool. ENDIF. ENDCASE. IF rr_data IS BOUND. ASSIGN rr_data->* TO . restore_type( EXPORTING json = json length = length CHANGING data = ). ENDIF. ENDMETHOD. "GENERATE_INT * ---------------------------------------------------------------------------------------+ * | Instance Protected Method ZCL_JSON->GENERATE_INT_EX * +-------------------------------------------------------------------------------------------------+ * | [--->] JSON TYPE JSON * | [--->] LENGTH TYPE I * | [<-->] DATA TYPE DATA * | [<-->] OFFSET TYPE I * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- METHOD get_fields. DATA: lt_symbols TYPE t_t_symbol, lv_name TYPE char128, ls_field LIKE LINE OF rt_fields. FIELD-SYMBOLS: LIKE LINE OF lt_symbols, LIKE LINE OF mt_name_mappings. lt_symbols = get_symbols( type_descr = type_descr data = data object = object include_aliases = abap_true ). LOOP AT lt_symbols ASSIGNING WHERE read_only EQ abap_false. MOVE-CORRESPONDING TO ls_field. " insert as UPPER CASE INSERT ls_field INTO TABLE rt_fields. " insert as lower case * TRANSLATE ls_field-name TO LOWER CASE. * INSERT ls_field INTO TABLE rt_fields. " as pretty printed IF mv_pretty_name NE pretty_mode-none AND mv_pretty_name NE pretty_mode-low_case. format_name -name mv_pretty_name ls_field-name. INSERT ls_field INTO TABLE rt_fields. " let us check for not well formed canelCase to be compatible with old logic lv_name = ls_field-name. TRANSLATE lv_name(1) TO UPPER CASE. ls_field-name = lv_name. INSERT ls_field INTO TABLE rt_fields. ENDIF. ENDLOOP. ENDMETHOD. "GET_FIELDS * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- METHOD get_symbols. DATA: comp_tab TYPE cl_abap_structdescr=>component_table, symb_tab LIKE result, symb LIKE LINE OF symb_tab, elem_descr TYPE REF TO cl_abap_elemdescr, class_descr TYPE REF TO cl_abap_classdescr, struct_descr TYPE REF TO cl_abap_structdescr. FIELD-SYMBOLS: LIKE LINE OF comp_tab, LIKE LINE OF cl_abap_objectdescr=>attributes, LIKE LINE OF mt_name_mappings, TYPE any. IF type_descr->kind EQ cl_abap_typedescr=>kind_struct. struct_descr ?= type_descr. comp_tab = struct_descr->get_components( ). LOOP AT comp_tab ASSIGNING . IF -name IS NOT INITIAL AND ( -as_include EQ abap_false OR include_aliases EQ abap_true OR mv_expand_includes EQ abap_false ). symb-name = -name. symb-type = -type. IF data IS BOUND. IF mv_conversion_exits EQ abap_true AND symb-type->kind EQ cl_abap_typedescr=>kind_elem. elem_descr ?= symb-type. symb-convexit_in = get_convexit_func( elem_descr = elem_descr input = abap_true ). symb-convexit_out = get_convexit_func( elem_descr = elem_descr input = abap_false ). ENDIF. is_compressable symb-type symb-name symb-compressable. ASSIGN data->(symb-name) TO . GET REFERENCE OF INTO symb-value. format_name symb-name mv_pretty_name symb-header. CONCATENATE `"` symb-header `":` INTO symb-header. ENDIF. APPEND symb TO result. ENDIF. IF -as_include EQ abap_true AND mv_expand_includes EQ abap_true. struct_descr ?= -type. symb_tab = get_symbols( type_descr = struct_descr include_aliases = include_aliases ). LOOP AT symb_tab INTO symb. CONCATENATE symb-name -suffix INTO symb-name. IF data IS BOUND. IF mv_conversion_exits EQ abap_true AND symb-type->kind EQ cl_abap_typedescr=>kind_elem. elem_descr ?= symb-type. symb-convexit_in = get_convexit_func( elem_descr = elem_descr input = abap_true ). symb-convexit_out = get_convexit_func( elem_descr = elem_descr input = abap_false ). ENDIF. is_compressable symb-type symb-name symb-compressable. ASSIGN data->(symb-name) TO . GET REFERENCE OF INTO symb-value. format_name symb-name mv_pretty_name symb-header. CONCATENATE `"` symb-header `":` INTO symb-header. ENDIF. APPEND symb TO result. ENDLOOP. ENDIF. ENDLOOP. ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_class. class_descr ?= type_descr. LOOP AT class_descr->attributes ASSIGNING WHERE is_constant IS INITIAL AND alias_for IS INITIAL AND ( is_interface IS INITIAL OR type_kind NE cl_abap_typedescr=>typekind_oref ). ASSIGN object->(-name) TO . CHECK sy-subrc IS INITIAL. " we can only assign to public attributes symb-name = -name. symb-read_only = -is_read_only. symb-type = class_descr->get_attribute_type( -name ). IF mv_conversion_exits EQ abap_true AND symb-type->kind EQ cl_abap_typedescr=>kind_elem. elem_descr ?= symb-type. symb-convexit_in = get_convexit_func( elem_descr = elem_descr input = abap_true ). symb-convexit_out = get_convexit_func( elem_descr = elem_descr input = abap_false ). ENDIF. is_compressable symb-type symb-name symb-compressable. GET REFERENCE OF INTO symb-value. format_name symb-name mv_pretty_name symb-header. CONCATENATE `"` symb-header `":` INTO symb-header. APPEND symb TO result. ENDLOOP. ENDIF. ENDMETHOD. "GET_SYMBOLS * ---------------------------------------------------------------------------------------+ * | Instance Protected Method ZCL_JSON->IS_COMPRESSABLE * +-------------------------------------------------------------------------------------------------+ * | [--->] TYPE_DESCR TYPE REF TO CL_ABAP_TYPEDESCR * | [--->] NAME TYPE CSEQUENCE * | [<-()] RV_COMPRESS TYPE ABAP_BOOL * +-------------------------------------------------------------------------------------- METHOD is_compressable. rv_compress = abap_true. ENDMETHOD. "IS_COMPRESSABLE * ---------------------------------------------------------------------------------------+ * | Instance Protected Method ZCL_JSON->PRETTY_NAME * +-------------------------------------------------------------------------------------------------+ * | [--->] IN TYPE CSEQUENCE * | [<-()] OUT TYPE STRING * +-------------------------------------------------------------------------------------- METHOD pretty_name. DATA: tokens TYPE TABLE OF char128, cache LIKE LINE OF mt_name_mappings. FIELD-SYMBOLS: LIKE LINE OF tokens, LIKE LINE OF mt_name_mappings. READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING . IF sy-subrc IS INITIAL. out = -json. ELSE. out = in. REPLACE ALL OCCURRENCES OF `__` IN out WITH `*`. TRANSLATE out TO LOWER CASE. TRANSLATE out USING `/_:_~_`. SPLIT out AT `_` INTO TABLE tokens. LOOP AT tokens ASSIGNING FROM 2. TRANSLATE (1) TO UPPER CASE. ENDLOOP. CONCATENATE LINES OF tokens INTO out. REPLACE ALL OCCURRENCES OF `*` IN out WITH `_`. cache-abap = in. cache-json = out. INSERT cache INTO TABLE mt_name_mappings. INSERT cache INTO TABLE mt_name_mappings_ex. ENDIF. ENDMETHOD. "PRETTY_NAME * ---------------------------------------------------------------------------------------+ * | Instance Protected Method ZCL_JSON->PRETTY_NAME_EX * +-------------------------------------------------------------------------------------------------+ * | [--->] IN TYPE CSEQUENCE * | [<-()] OUT TYPE STRING * +-------------------------------------------------------------------------------------- METHOD pretty_name_ex. DATA: tokens TYPE TABLE OF char128, cache LIKE LINE OF mt_name_mappings. FIELD-SYMBOLS: LIKE LINE OF tokens, LIKE LINE OF mt_name_mappings. READ TABLE mt_name_mappings WITH TABLE KEY abap = in ASSIGNING . IF sy-subrc IS INITIAL. out = -json. ELSE. out = in. TRANSLATE out TO LOWER CASE. TRANSLATE out USING `/_:_~_`. REPLACE ALL OCCURRENCES OF `__e__` IN out WITH `!`. REPLACE ALL OCCURRENCES OF `__n__` IN out WITH `#`. REPLACE ALL OCCURRENCES OF `__d__` IN out WITH `$`. REPLACE ALL OCCURRENCES OF `__p__` IN out WITH `%`. REPLACE ALL OCCURRENCES OF `__m__` IN out WITH `&`. REPLACE ALL OCCURRENCES OF `__s__` IN out WITH `*`. REPLACE ALL OCCURRENCES OF `__h__` IN out WITH `-`. REPLACE ALL OCCURRENCES OF `__t__` IN out WITH `~`. REPLACE ALL OCCURRENCES OF `__l__` IN out WITH `/`. REPLACE ALL OCCURRENCES OF `__c__` IN out WITH `:`. REPLACE ALL OCCURRENCES OF `__v__` IN out WITH `|`. REPLACE ALL OCCURRENCES OF `__a__` IN out WITH `@`. REPLACE ALL OCCURRENCES OF `__o__` IN out WITH `.`. REPLACE ALL OCCURRENCES OF `___` IN out WITH `.`. REPLACE ALL OCCURRENCES OF `__` IN out WITH `"`. SPLIT out AT `_` INTO TABLE tokens. LOOP AT tokens ASSIGNING FROM 2. TRANSLATE (1) TO UPPER CASE. ENDLOOP. CONCATENATE LINES OF tokens INTO out. REPLACE ALL OCCURRENCES OF `"` IN out WITH `_`. cache-abap = in. cache-json = out. INSERT cache INTO TABLE mt_name_mappings. INSERT cache INTO TABLE mt_name_mappings_ex. ENDIF. ENDMETHOD. "PRETTY_NAME_EX * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON=>RAW_TO_STRING * +-------------------------------------------------------------------------------------------------+ * | [--->] IV_XSTRING TYPE XSTRING * | [--->] IV_ENCODING TYPE ABAP_ENCODING(optional) * | [<-()] RV_STRING TYPE STRING * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- METHOD restore. DATA: mark LIKE offset, match LIKE offset, ref_descr TYPE REF TO cl_abap_refdescr, data_descr TYPE REF TO cl_abap_datadescr, data_ref TYPE REF TO data, object_ref TYPE REF TO object, fields LIKE field_cache, name_json TYPE string. FIELD-SYMBOLS: TYPE any, LIKE LINE OF field_cache. 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 . APPEND 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 . fields = get_fields( type_descr = type_descr data = data_ref ). restore( EXPORTING json = json length = length type_descr = type_descr field_cache = fields CHANGING data = offset = offset ). RETURN. ENDIF. ENDIF. IF fields IS INITIAL AND type_descr IS NOT INITIAL AND type_descr->kind EQ type_descr->kind_struct. GET REFERENCE OF data INTO data_ref. fields = get_fields( type_descr = type_descr data = data_ref ). ENDIF. eat_white. eat_char `{`. eat_white. WHILE offset < length AND json+offset(1) NE `}`. eat_name name_json. eat_white. eat_char `:`. eat_white. READ TABLE fields WITH TABLE KEY name = name_json ASSIGNING . IF sy-subrc IS NOT INITIAL. TRANSLATE name_json TO UPPER CASE. READ TABLE fields WITH TABLE KEY name = name_json ASSIGNING . ENDIF. IF sy-subrc IS INITIAL. ASSIGN -value->* TO . restore_type( EXPORTING json = json length = length type_descr = -type convexit = -convexit_in CHANGING data = offset = offset ). ELSE. restore_type( EXPORTING json = json length = length CHANGING offset = offset ). ENDIF. eat_white. IF offset < length AND json+offset(1) NE `}`. eat_char `,`. eat_white. ELSE. EXIT. ENDIF. ENDWHILE. eat_char `}`. ENDMETHOD. "RESTORE * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- METHOD restore_type. DATA: mark LIKE offset, match LIKE offset, sdummy TYPE string, "#EC NEEDED rdummy TYPE REF TO data, "#EC NEEDED pos LIKE offset, line TYPE REF TO data, key_ref TYPE REF TO data, data_ref TYPE REF TO data, key_name TYPE string, key_value TYPE string, lt_fields LIKE field_cache, lt_symbols TYPE t_t_symbol, lv_ticks TYPE string, lv_offset TYPE string, lv_convexit LIKE convexit, lo_exp TYPE REF TO cx_root, elem_descr TYPE REF TO cl_abap_elemdescr, table_descr TYPE REF TO cl_abap_tabledescr, data_descr TYPE REF TO cl_abap_datadescr. FIELD-SYMBOLS: TYPE any, TYPE any, TYPE data, LIKE LINE OF lt_fields,
TYPE ANY TABLE, LIKE LINE OF lt_symbols. lv_convexit = convexit. IF type_descr IS INITIAL AND data IS SUPPLIED. type_descr = cl_abap_typedescr=>describe_by_data( data ). IF mv_conversion_exits EQ abap_true AND lv_convexit IS INITIAL AND type_descr->kind EQ cl_abap_typedescr=>kind_elem. elem_descr ?= type_descr. lv_convexit = get_convexit_func( elem_descr = elem_descr input = abap_true ). ENDIF. ENDIF. eat_white. TRY . IF type_descr IS NOT INITIAL AND type_descr->absolute_name EQ mc_json_type. " skip deserialization mark = offset. restore_type( EXPORTING json = json length = length CHANGING offset = offset ). match = offset - mark. data = json+mark(match). ENDIF. CASE json+offset(1). WHEN `{`. " object IF type_descr IS NOT INITIAL. IF mv_assoc_arrays EQ c_bool-true AND type_descr->kind EQ cl_abap_typedescr=>kind_table. table_descr ?= type_descr. data_descr = table_descr->get_table_line_type( ). IF table_descr->has_unique_key IS NOT INITIAL. eat_char `{`. eat_white. IF json+offset(1) NE `}`. ASSIGN data TO
. CLEAR
. CREATE DATA line LIKE LINE OF
. ASSIGN line->* TO . lt_fields = get_fields( type_descr = data_descr data = line ). IF table_descr->key_defkind EQ table_descr->keydefkind_user AND lines( table_descr->key ) EQ 1. READ TABLE table_descr->key INDEX 1 INTO key_name. READ TABLE lt_fields WITH TABLE KEY name = key_name ASSIGNING . key_ref = -value. IF mv_assoc_arrays_opt EQ c_bool-true. lt_symbols = get_symbols( type_descr = data_descr data = line ). DELETE lt_symbols WHERE name EQ key_name. IF lines( lt_symbols ) EQ 1. READ TABLE lt_symbols INDEX 1 ASSIGNING . ENDIF. ENDIF. ENDIF. eat_white. WHILE offset < length AND json+offset(1) NE `}`. CLEAR . eat_name key_value. eat_white. eat_char `:`. eat_white. IF IS ASSIGNED. ASSIGN -value->* TO . restore_type( EXPORTING json = json length = length type_descr = -type convexit = -convexit_in CHANGING data = offset = offset ). ELSE. restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fields CHANGING data = offset = offset ). ENDIF. IF table_descr->key_defkind EQ table_descr->keydefkind_user. IF key_ref IS BOUND. ASSIGN key_ref->* TO . IF IS INITIAL. = key_value. ENDIF. ENDIF. ELSEIF IS INITIAL. = key_value. ENDIF. INSERT INTO TABLE
. eat_white. IF offset < length AND json+offset(1) NE `}`. eat_char `,`. eat_white. ELSE. EXIT. ENDIF. ENDWHILE. ELSE. CLEAR data. ENDIF. eat_char `}`. ELSE. restore( EXPORTING json = json length = length CHANGING offset = offset ). ENDIF. ELSEIF type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. IF data IS INITIAL. generate_int_ex( EXPORTING json = json length = length CHANGING offset = offset data = data ). ELSE. data_ref ?= data. type_descr = cl_abap_typedescr=>describe_by_data_ref( data_ref ). ASSIGN data_ref->* TO . restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING data = offset = offset ). ENDIF. ELSE. restore( EXPORTING json = json length = length type_descr = type_descr field_cache = field_cache CHANGING data = data offset = offset ). ENDIF. ELSE. restore( EXPORTING json = json length = length CHANGING offset = offset ). ENDIF. WHEN `[`. " array IF type_descr IS NOT INITIAL AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. IF data IS INITIAL. generate_int_ex( EXPORTING json = json length = length CHANGING offset = offset data = data ). ELSE. data_ref ?= data. type_descr = cl_abap_typedescr=>describe_by_data_ref( data_ref ). ASSIGN data_ref->* TO . restore_type( EXPORTING json = json length = length type_descr = type_descr CHANGING data = offset = offset ). ENDIF. ELSE. eat_char `[`. eat_white. IF json+offset(1) NE `]`. IF type_descr IS NOT INITIAL AND type_descr->kind EQ cl_abap_typedescr=>kind_table. table_descr ?= type_descr. data_descr = table_descr->get_table_line_type( ). ASSIGN data TO
. CLEAR
. CREATE DATA line LIKE LINE OF
. ASSIGN line->* TO . lt_fields = get_fields( type_descr = data_descr data = line ). WHILE offset < length AND json+offset(1) NE `]`. CLEAR . restore_type( EXPORTING json = json length = length type_descr = data_descr field_cache = lt_fields CHANGING data = offset = offset ). INSERT INTO TABLE
. eat_white. IF offset < length AND json+offset(1) NE `]`. eat_char `,`. eat_white. ELSE. EXIT. ENDIF. ENDWHILE. ELSE. " skip array eat_white. WHILE offset < length AND json+offset(1) NE `]`. restore_type( EXPORTING json = json length = length CHANGING offset = offset ). eat_white. IF offset < length AND json+offset(1) NE `]`. eat_char `,`. eat_white. ELSE. EXIT. ENDIF. ENDWHILE. IF type_descr IS NOT INITIAL. eat_char `]`. throw_error. ENDIF. ENDIF. ELSE. CLEAR data. ENDIF. eat_char `]`. ENDIF. WHEN `"`. " string eat_string sdummy. IF type_descr IS NOT INITIAL. " unescape string IF sdummy IS NOT INITIAL. IF type_descr->kind EQ cl_abap_typedescr=>kind_elem. elem_descr ?= type_descr. IF lv_convexit IS NOT INITIAL. TRY . CALL FUNCTION lv_convexit EXPORTING input = sdummy IMPORTING output = data EXCEPTIONS error_message = 2 OTHERS = 1. IF sy-subrc IS INITIAL. RETURN. ENDIF. CATCH cx_root. "#EC NO_HANDLER ENDTRY. ENDIF. CASE elem_descr->type_kind. WHEN cl_abap_typedescr=>typekind_char. IF elem_descr->output_length EQ 1 AND mc_bool_types CS elem_descr->absolute_name. IF sdummy(1) CA `XxTt1`. data = c_bool-true. ELSE. data = c_bool-false. ENDIF. RETURN. ENDIF. WHEN cl_abap_typedescr=>typekind_xstring. string_to_xstring( EXPORTING in = sdummy CHANGING out = data ). RETURN. WHEN cl_abap_typedescr=>typekind_hex. " support for Edm.Guid REPLACE FIRST OCCURRENCE OF REGEX `^([0-9A-F]{8})-([0-9A-F]{4})-([0-9A-F]{4})-([0-9A-F]{4})-([0-9A-F]{12})$` IN sdummy WITH `$1$2$3$4$5` REPLACEMENT LENGTH match. "#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 . = sdummy. data ?= rdummy. RETURN. ELSE. throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTED ENDIF. data = sdummy. ELSEIF type_descr->kind EQ cl_abap_typedescr=>kind_elem. CLEAR data. ELSE. throw_error. " Other wise dumps with OBJECTS_MOVE_NOT_SUPPORTED ENDIF. ENDIF. WHEN `-` OR `0` OR `1` OR `2` OR `3` OR `4` OR `5` OR `6` OR `7` OR `8` OR `9`. " number IF type_descr IS NOT INITIAL. IF type_descr->kind EQ type_descr->kind_ref AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. eat_number sdummy. "#EC NOTEXT match = strlen( sdummy ). IF sdummy CS '.'. " float. CREATE DATA rdummy TYPE f. ELSEIF match GT 9. " packed CREATE DATA rdummy TYPE p. ELSE. " integer CREATE DATA rdummy TYPE i. ENDIF. ASSIGN rdummy->* TO . = sdummy. data ?= rdummy. ELSEIF type_descr->kind EQ type_descr->kind_elem. IF lv_convexit IS NOT INITIAL. TRY . eat_number sdummy. "#EC NOTEXT CALL FUNCTION lv_convexit EXPORTING input = sdummy IMPORTING output = data EXCEPTIONS error_message = 2 OTHERS = 1. IF sy-subrc IS INITIAL. RETURN. ENDIF. CATCH cx_root. "#EC NO_HANDLER ENDTRY. ENDIF. eat_number data. "#EC NOTEXT ELSE. eat_number sdummy. "#EC NOTEXT throw_error. ENDIF. ELSE. eat_number sdummy. "#EC NOTEXT ENDIF. WHEN OTHERS. " boolean, e.g true/false/null IF type_descr IS NOT INITIAL. IF type_descr->kind EQ type_descr->kind_ref AND type_descr->type_kind EQ cl_abap_typedescr=>typekind_dref. CREATE DATA rdummy TYPE bool. ASSIGN rdummy->* TO . eat_bool . "#EC NOTEXT data ?= rdummy. ELSEIF type_descr->kind EQ type_descr->kind_elem. eat_bool data. "#EC NOTEXT ELSE. eat_bool sdummy. "#EC NOTEXT throw_error. ENDIF. ELSE. eat_bool sdummy. "#EC NOTEXT ENDIF. ENDCASE. CATCH cx_sy_move_cast_error cx_sy_conversion_no_number cx_sy_conversion_overflow INTO lo_exp. CLEAR data. IF mv_strict_mode EQ abap_true. RAISE EXCEPTION TYPE cx_sy_move_cast_error EXPORTING previous = lo_exp. ENDIF. ENDTRY. ENDMETHOD. "RESTORE_TYPE * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | 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 * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON=>STRING_TO_RAW * +-------------------------------------------------------------------------------------------------+ * | [--->] IV_STRING TYPE STRING * | [--->] IV_ENCODING TYPE ABAP_ENCODING(optional) * | [<-()] RV_XSTRING TYPE XSTRING * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON=>STRING_TO_XSTRING * +-------------------------------------------------------------------------------------------------+ * | [--->] IN TYPE STRING * | [<-->] OUT TYPE ANY * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON=>TRIBOOL_TO_BOOL * +-------------------------------------------------------------------------------------------------+ * | [--->] IV_TRIBOOL TYPE TRIBOOL * | [<-()] RV_BOOL TYPE BOOL * +-------------------------------------------------------------------------------------- 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 * ---------------------------------------------------------------------------------------+ * | Static Protected Method ZCL_JSON=>UNESCAPE * +-------------------------------------------------------------------------------------------------+ * | [--->] ESCAPED TYPE STRING * | [<-()] UNESCAPED TYPE STRING * +-------------------------------------------------------------------------------------- METHOD unescape. DATA: lv_offset TYPE i, lv_match TYPE i, lv_delta TYPE i, lv_length TYPE i, lv_offset_e TYPE i, lv_length_e TYPE i, lv_unicode_symb TYPE c, lv_unicode_escaped TYPE string, lt_matches TYPE match_result_tab. FIELD-SYMBOLS: LIKE LINE OF lt_matches. " see reference for escaping rules in JSON RFC " https://www.ietf.org/rfc/rfc4627.txt unescaped = escaped. lv_length = strlen( unescaped ). FIND FIRST OCCURRENCE OF REGEX `\\[rntfbu]` IN unescaped RESPECTING CASE. IF sy-subrc IS INITIAL. FIND ALL OCCURRENCES OF REGEX `\\.` IN unescaped RESULTS lt_matches RESPECTING CASE. LOOP AT lt_matches ASSIGNING . lv_match = -offset - lv_delta. lv_offset = lv_match + 1. CASE unescaped+lv_offset(1). WHEN `r`. REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>cr_lf(1). lv_delta = lv_delta + 1. WHEN `n`. REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>newline. lv_delta = lv_delta + 1. WHEN `t`. REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>horizontal_tab. lv_delta = lv_delta + 1. WHEN `f`. REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>form_feed. lv_delta = lv_delta + 1. WHEN `b`. REPLACE SECTION OFFSET lv_match LENGTH 2 OF unescaped WITH cl_abap_char_utilities=>backspace. lv_delta = lv_delta + 1. WHEN `u`. lv_offset = lv_offset + 1. lv_offset_e = lv_offset + 4. lv_length_e = lv_length + lv_delta. IF lv_offset_e LE lv_length_e. lv_unicode_escaped = unescaped+lv_offset(4). TRANSLATE lv_unicode_escaped TO UPPER CASE. lv_unicode_symb = cl_abap_conv_in_ce=>uccp( lv_unicode_escaped ). IF lv_unicode_symb NE mc_cov_error. REPLACE SECTION OFFSET lv_match LENGTH 6 OF unescaped WITH lv_unicode_symb. lv_delta = lv_delta + 5. ENDIF. ENDIF. ENDCASE. ENDLOOP. ENDIF. " based on RFC mentioned above, _any_ character can be escaped, and so shall be enscaped " the only exception is Unicode symbols, that shall be kept untouched, while serializer does not handle them " unescaped singe characters, e.g \\, \", \/ etc REPLACE ALL OCCURRENCES OF REGEX `\\(.)` IN unescaped WITH `$1` RESPECTING CASE. ENDMETHOD. "UNESCAPE * ---------------------------------------------------------------------------------------+ * | Static Public Method ZCL_JSON=>XSTRING_TO_STRING * +-------------------------------------------------------------------------------------------------+ * | [--->] IN TYPE ANY * | [<-()] OUT TYPE STRING * +-------------------------------------------------------------------------------------- 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.

点击下图红框按钮。

ABAP Json和对象的转换_第3张图片

复制粘贴下面代码

*"* 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 . "#EC WARNOK
      if sy-subrc is initial.
        &3 = -json.
      else.
        &3 = &1.
        translate &3 to lower case.                       "#EC SYNTCHAR
      endif.
    when pretty_mode-user.
      read table mt_name_mappings with table key abap = &1 assigning . "#EC WARNOK
      if sy-subrc is initial.
        &3 = -json.
      else.
        &3 = &1.
      endif.
    when pretty_mode-low_case.
      &3 = &1.
      translate &3 to lower case.                         "#EC SYNTCHAR
    when others.
      &3 = &1.
  endcase.
END-OF-DEFINITION.

DEFINE throw_error.
  raise exception type cx_sy_move_cast_error.
END-OF-DEFINITION.

DEFINE while_offset_cs.
*  >= 7.02 alternative
*  pos = find_any_not_of( val = json sub = &1 off = offset ).
*  if pos eq -1. offset = length.
*  else. offset = pos. endif.

* < 7.02
  while offset < length.
    find first occurrence of json+offset(1) in &1.
    if sy-subrc is not initial.
      exit.
    endif.
    offset = offset + 1.
  endwhile.
* < 7.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.

测试结果

ABAP Json和对象的转换_第4张图片

你可能感兴趣的:(SAP,json,sap,abap)