GRC
HR
SCM
CRM
BI
Expand +


Article

 

Get Data From Any Table in Another SAP System

A Generic Way in ABAP

by George Chen

July 2, 2015

Learn a new way to load data from any table in any SAP system to any other SAP system. See how to use a Remote Function Call (RFC) function module call, Runtime Type Service (RTTS), and JavaScript Object Notation (JSON) serialization/deserialization.

 

Say you want to get the contents of a table from one of your SAP systems (called the source system) into a current system (called the client system). Most of the time if you want to access the table content of a source system, you need to:

  • Check to see if the content is in the standard business content
  • Check to see if business content is installed on both the source system and the target system
  • Ensure the business content is the same version on both systems — If yes, you need to activate the business content, build or activate the transformation and InfoProvider, and start data extraction. If no, you need to build your own customized data source, sync it on both systems, build the transformation and InfoProvider, and start extraction.

The business content mostly covers master data and transaction data. Sometimes you need to access configuration data. Here are some examples:

  • In Trade Promotion Management (TPM)–Business Planning and Simulation (BPS) integration, you need to get the BPS planning profile information into the context of a Customer Relationship Management (CRM) environment. Even though you could get this through the IMG, you don’t have the flexibility in ABAP programming. The BPS planning profile can be connected to TPM through the IMG and planning data can be retrieved to TPM applications. However, what if you want to incorporate BPS planning data anywhere in TPM Web Dynpro? ABAP programming with this solution provides the flexibility.
  • When doing customizing development in Web Dynpro ABAP for TPM planning, you can get multiple BPS planning profiles and compare. This usually is not a big amount of data but something critical that you need to look up in coding as a reference.
  • You want to check the material cost in table MBEW of an ERP Central Component (ECC) system when you build a report in CRM, or you need to get planning results from Enterprise Performance Management (SAP EPM)/Business Planning and Consolidation (SAP BPC) into a CRM report.
  • Instead of getting data into an SAP Business Warehouse (SAP BW) staging InfoProvider, you may want to get information from the source system at run time and release the data once you finish the work (e.g., you don’t want to maintain or update the data in the target system on a daily basis).
  • In addition to extracting data without business content and flexibility as shown in the TPM example above, a third requirement is that ideally you want to have one generic solution for all situations. It would be a lot of work if you needed to write 20 different program/function modules, one for each table. It would be best to have one program/function module for all situations.
Architectural Trade-Offs

Inspired by SAP’s transition from .NET Connector 2.0 to .NET Connector 3.0, I wanted a tool to freely obtain data from any SAP system to any SAP system, independent of business content and of the output restriction. Of course a security check would need to be added.

After finishing this development, I checked SAP’s standard function module RFC_READ_TABLE. I then extended my reading into SAP Note 382318. RFC_READ_TABLE is also a generic functionality to get table content. I feel you still need this generic functionality to access table content of other systems without relying on business content. However, as stated in SAP Note 382318 there are three issues with function module RFC_READ_TABLE: security, limit on row size, and limit on fixed buffer.

I needed an unrestricted generic format of output (meaning no limit on row size). However, the standard output TAB512 (table with a 512-byte field) set the row size to 512 bytes only. The solution is to export data in a string. A better solution would be export data in a JavaScript Object Notation (JSON) format, which is lighter and easy to integrate with other SAP or non-SAP web applications.

I tested extraction for text table STXH, which is available in all SAP systems. Of 60K entries with 31 fields, it generates 40MB of output data compared with 60MB of data from SAP standard function module RFC_READ_TABLE. My output is 30 percent lighter than the table output from RFC_READ_TABLE. I am continuing to think of how to improve the performance of JSON deserialization and to compact the JSON output.

The Process

I’m introducing a new, convenient way to get the information from any system into any system. By the end of this article, you will be able to log in to both the source and the client (target) systems, implement this program on both sides, and call the program to get the information you need.

My assumptions are that you:

  • Have a Remote Function Call (RFC) connection between the systems
  • Either don’t want to use business content/data sources, don’t want to create a customized data source, or the data source is not available
  • Want this to be a generic solution that is applicable to generally all SAP transparent tables for moderate data volume. (I tested this method for 60K records of 40MB data, which came back in 131 seconds).

Figure 1 shows the solution.


Figure 1
Program flow for extracting data from table MBEW of the ECC system to the client system

Let’s look at an example. Assume you are in an SAP BW system and want to quickly access some material planning cost and future price information from ECC in order to compare and generate the variance against actual cost. With this method, you create an RFC function module Z_GET_TBLCNT on both sides of the systems. This is the core of this solution:

  • Step 1. An RFC sends a request from SAP BW to ECC.
  • Step 2. The receiver (on the ECC side) function module Z_GET_TBLCNT queries data from table MBEW for the material cost and future price for the designated selection. Before the system queries the data, there will be a security check to ensure the caller user-ID is authorized to view the content of the table.
  • Step 3. The query result comes back to function module Z_GET_TBLCNT.
  • Step 4. The result and metadata that describes the structure of the result are sent back to the send function module Z_GET_TBLCNT.
  • Step 5. The get/put are all handled by a utility class called ZCL_BW_UTILITY.
  • Step 6. Developers can create their own program or invoke an instance of the class ZCL_BW_UTILITY anywhere in the program environment to start the request.

From a design standpoint (Figure 2), the core starts at step 1 to start the RFC of the function module Z_GET_TBLCNT. From a data access standpoint, you create a utility class to store and fetch data. You can invoke an instance of the utility classes from any program or any routine.


Figure 2
Design implementation application programming interface (API)

(Note: As an optional output to a generic string output or string table output, I made a JSON import/export in function module Z_GET_TBLCNT. Since this function module works both in/out, I did JSON serialization/deserialization to convert data between the ABAP structure and the JSON format. The method I take is from Alex Arseniev’s generic transformation class.

Here are my design thoughts regarding output. The output is independent of actual content extraction logic. The output can be in various formats, of which JSON is one:

  • You could create your own JSON conversion.
  • You could choose not to spit out data in JSON format.
  • Since this function module is designed to be generic, however, the essence is that you need to export data in a generic structure, and you need to export the metadata (the data that describes your data) in a generic structure)

Now you design function module Z_GET_TBLCNT. The function module Z_GET_TBLCNT is created in both the source system and client system. Depending on the different values passed in parameter I_IND, the function module triggers a different part of the code. If I_IND is C (standing client system), it behaves as a caller with the RFC destination in parameter I_DEST. Any program interface can start this process by calling Z_GET_TBLCNT with I_IND = ‘C’ and an RFC destination name (Figure 3).


Figure 3
Call the function module with I_IND='C'

If in a program you call the function module with I_IND = ‘C’ from the client system as shown in Figure 4, you jump to line 93 of the function module ‘Z_GET_TBLCNT’ in Figure 3. Line 93 starts an RFC from the client system to the source system. This is step 2. The RFC sends a request from SAP BW to ECC.

Call function ‘Z_GET_TBLCNT’
EXPORTING
ITAB_NAME = ITAB_NAME
I_IND = ‘C’
……

Figure 4
Calling function module Z_GET_TBLCNT with I_IND = ‘C’

With this I_IND, the two functions (sender and receiver) are combined into one function module. The installation work is easier with the same function module installed on both systems. You avoid the hassle of having a source version and a client version of the function module.

The query data (step 2), query result (step 3), data, and metadata (step 4) are invisible in Figure 3 because these happened in the source system. Figure 3 shows what happened in the receiver system as a caller. The details of steps 2 through 4 in the callee (or the source system) are shown in Figure 1. Steps 2 through 4 are accomplished by calling function module Z_GET_TBLCNT with I_IND = ‘S’.

In the source system, call the function module Z_GET_TBLCNT with I_IND = ‘S’.

Before querying the data, you should do a security check as shown in Figure 5. Then you query the data. If you query data in table MBEW, line 60 would have the itab_name = ‘MBEW’. At run time line 42 becomes Select * from mbew into table <lt_data>.


Figure 5
Security check done before querying the data in the source system

Line 63 in Figure 6 shows how to call function module DDIF_FIELDINFO_GET.


Figure 6
Get the metadata of the data

Secondly, you need to call function module DDIF_FIELDINFO_GET to get the metadata. When you give a table name in variable itab_name, you get back metadata in lt_struct, which is a table of SAP standard structure DFIES. The table is shown as DFIED_TAB in Figure 7. This lt_struct is the metadata that describes the table. In my example it is the metadata of table MBEW.


Figure 7
Structure information about table MBEW

Figure 8 shows the Data Dictionary of structure DFIES.


Figure 8
Metadata: the structure of DFIES

Now that I have the data in <LT_DATA> and the metadata in LT_STRUCT, I need to pass these back to the caller (the receiver, or the target system). Since this is a generic solution I have to pass data in a generic structure and I have to tell the caller what the structure of the incoming data is at run time.

The LT_STRUCT as a table of structure DFIES tells the caller what the structure of the incoming data is. The structure of LT_STRUCT is DFIES, which is available in all SAP systems. Therefore, the caller is able to understand this without a problem.

The <LT_DATA> is a table with a specified structure. I can’t pass <LT_DATA> back to the caller. Since this is an RFC-enabled function module, I have to pass everything by value (i.e., I can’t pass by reference or any object) in a generic data format. Here I have a few options. The one I pick up here is to serialize <LT_DATA> to JSON XML. As an alternative, I could convert <LT_DATA> to a table of strings to export, then on the receiver side I need to import the table of strings and then convert it back to the same structure as that of <LT_DATA>. However, either way I need to know what the structure of <LT_DATA> is on the receiver/caller side. This is what the LT_STRUCT carries in from function module DDIF_FIELDINFO_GET.

Figure 9 shows how data in <lt_data> is serialized into JSON format string in c_data and how the data structure lt_struct is serialized into a JSON format string in c_struct.


Figure 9
Serialize the data and metadata

Figure 9 shows how I serialize <lt_data> into c_data. Next, I restore the data from the JSON XML to the ABAP structure according to lt_struct.

Step 3. Pass the <LT_DATA> and LT_STRUCT into the JSON format.

Step 4. The data, in JSON format, is loaded into the caller (i.e., the target system), as shown in lines 98 and 99 in Figure 10. This sends data back to the caller (i.e., the target system in lines 98 and line 99 in Figure 10).


Figure 10
Receiving data and metadata in JSON XML format

Let’s see how data is received in the target system (i.e., the SAP BW system).

Now I have data received in lv_JSON and metadata in lv_struct. Both are in JSON XML format. Line 103 to line 108 in Figure 11 show how I convert the table structure information from JSON XML format to an ABAP structure.


Figure 11
Deserialize metadata back to ABAP from JSON

Depending on the storage preference carried in parameter i_store_pref, leave the metadata of the data and the data itself as a string for i_store_ref = ‘S’, or deserialize them into ABAP tables, if i_store_ref = ‘T’.

If the storage reference is a table, meaning that the incoming data is a table, I deserialize the metadata into lt_struct. Since JSON does not carry type information, you have to know the expected structure before you deserialize it. The good news is this table of structure DFIES is standard, available in all SAP systems. Now I have the metadata from the source system’s DDIF_FIELD_INFO_GET carried in lt_struct. It is then converted to lt_component with a list of components and recreated as ls_struct, as shown in Figure 12.


Figure 12
Recreate the structure

This flow chart (Figure 13) shows how the metadata is obtained from the source system, how it is carried over to the client system, and how it is rebuilt.


Figure 13
The route for the metadata

If the storage reference is a structure, meaning the incoming data is a structure, you just need to deserialize to get the structure (Figure 14). In most cases, you get a table of data (i.e., a storage reference as a table).


Figure 14
Deserialize data to the ABAP structure

The whole point to creating a structure reference in lr_struct is to create a structure and a table <LT_result> as the receiver for the JSON XML-fomatted data LV_JSON.

Step 5. Pack the metadata of the data and the data itself (either in string format or ABAP table format) into reference. Store them in a utility class ZCL_BW_UTILITY (step 5 in the topology diagram) via method PUT_DATA() as shown in Figure 15.


Figure 15
Method put_data() to ZCL_BW_UTILITY

Here you can pass the data and structure by reference to a utility class so that any programs, classes, and subroutines can access this class to fetch data. This way you isolate the function module from the data storage utility and, further, make them available for other APIs to call.

In Figure 15 you pass different parameters and sy-subrc is returned to indicate if it is successful. You can insert error messages here if needed. Figure 16 shows one way to check and insert an error message.


Figure 16
Error handling

Let’s look at the detail of the utility class ZCL_BW_UTILITY. Figure 17 shows the import parameters and the status return indicating if the method PUT_DATA is executed successfully or not. The import parameters include the table name as I_TABNAME, I_CA as the category to specify that the data stored is the actual data or the structure of the data, and I_TYPE to specify whether it is a table (multiple records) or a structure of data (i.e., one line of data).


Figure 17
Store data into class attribute dt_data

Here I store import data in a class attribute, associated with id = table name (MBEW) and category and type.

Figure 18 shows how I stored data in class attribute DT_DATA using method PUT_DATA(). Now you can see DT_DATA is an attribute of the class to store the data.


Figure 18
Class attribute DT_DATA

The DT_DATA is of the type TT_DATA. Figure 19 shows the definition of TT_DATA.

types:
    begin of TS_DATA ,
    id type tabname,
    category type char6,
  l_type type char6,
  l_data type ref to data,
    end of ts_data .
  types:
    tt_data type hashed TABLE OF ts_data  with UNIQUE key id category l_type .

Figure 19
TT_DATA definition

The following shows how you identify data with a type, table name, and category:

  • With l_type indicating whether the stored data is in the format of a table or in the format of a string
  • With id indicating the table name you queried
  • With category indicating whether the data stored is metadata of the data (‘STRUCT’) or data itself

This completes the work of getting table content from any SAP system and storing the data.

Step 6. To get the result of table MBEW or any table content, use the code in Figure 20 anywhere in any program.

DATA(LR_DATA) = ZCL_BW_UTILITY=>GET_INSTANCE()->GET_DATA(I_TABNAME = ‘MBEW’ I_CAT = ‘DATA’ I_TYPE = ‘TABLE’).

Figure 20
Sample code to get data from MBEW

DATA(LR_DATA) = ZCL_BW_UTILITY=>GET_INSTANCE()->GET_DATA(I_TABNAME = ‘MBEW’ I_CAT = ‘DATA’ I_TYPE = ‘TABLE’).

Figure 21 shows the method GET_DATA() to get the data from the class attribute DT_DATA to output.


Figure 21
GET_DATA method

Technical Features

The following shows how Runtime Type Services (RTTS) are used in this application.

Based on the metadata of data delivered by function module DDIF_FIELDINFO_GET, in the format of table of the SAP standard structure DFIES, you loop through the fields one by one. Depending on the data types:

  • If it is DATE type, you call cl_abap_elemdescr=>get_d( ).
  • If it is CHAR type, you call cl_abap_elemdescr=>get_c(), specifying the length
  • If it is PACKED number type, you call cl_abap_elemdescr=>get_p(), specifying the internal length and decimal places
  • If it is NUMC type, you call cl_abap_elemdescr=>get_n(), specifying the length

Figure 22 shows, from line 114 through line 130, how I loop through the table structure (here LT_STRUCT). Depending on the data element type, you create a different data type at run time.


Figure 22
Build a component table to create a structure

By looping through lt_struct, I create a table of element components in cl_abap_structdescr=>component_table format, and therefore I can call cl_abap_structdescr=>get( p_components = lt_component ) to get the handle. With the handle, I can create a structure and thus create a table at run time. With the table created, I have the appropriate container ready to receive deserialized data from the JSON format.

Utility Class ZCL_BW_UTILITY

The development of class ZCL_BW_UTILITY starts from method get_instance(). This method get_instance() is an application of the rule of singleton. The rule of singleton ensures that you use one and only one object at run time to save run time and system resources. Let’s take the analogy for the rule of singleton. If I need to drive to work, I will check see if my colleague (who happens to be my neighbor) is driving. If he is, I will carpool with him and I don’t have to drive. Here before I create an instance of the class, I will check, by using get_instance(), to see if there is an existing one that I can take. If yes, I will take the existing one (I am referring to m_ref in Figure 23). If not, I will create an instance.


Figure 23
Take an existing instance

In Figure 24 in the method get_instance() of class ZCL_BW_UTILITY, the object M_REF is Type Refer to ZCL_BW_UTILITY itself and is stored as a static public attribute.


Figure 24
Class attribute for a singleton

Secondly, with input parameters, you can put your data by method PUT_DATA(), which I explained before. Here just note the use of put_data (Figure 25).

Data: lc_util type ref to zcl_bw_utility.

Lc_util = zcl_bw_utility=>get_instance().

Lc_util->put_data( xxxxxx) .

Figure 25
Get the instance of the class

Or you can simply put it like a chain as shown in Figure 26.

Zcl_bw_utility=>get_instance( )->put_data( xxxxx ).

Figure 26
Get the instance of the class

Thirdly, you can get data by using GET_DATA( ).


Similarly, I can perform get data as I explained before (Figure 27).

Data(lr_dta) = Zcl_bw_utility=>get_instance( ).

lr_data->put_data( xxxxx ).

Figure 27
Call put_data()

Data Serialization and Deserialization

The class I am using is a local copy of the latest /UI2/CL_JSON, with credit to Alexey Arseniev. (reference: http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer).

Since this SAP standard class is still being evolved, I made a local copy of it to class zcl_ui2_JSON from the URL, as per Alexey’s suggestion, so that I can stick to it and make possible changes if I need to.

The advantage of this is I don’t have to create individual XSLT transformation programs, one for each ABAP structure or table. Instead, this is a generic class that employs a recursive function of dump() for serialization and restore_type() for deserialization to deal with a nested ABAP structure. I can serialize ABAP data into a JSON XML string and deserialize the JSON XML string back to ABAP data without the XSLT program, on the condition that I know my ABAP data type.

Code Reference

Figure 28 shows the content of function module Z_GET_TBLCNT.


*"----------------------------------------------------------------------

*"*"Local Interface:

*"  IMPORTING

*"     VALUE(ITAB_NAME) TYPE  TABNAME DEFAULT 'MBEW'

*"     VALUE(I_IND) TYPE  CHAR1

*"     VALUE(I_STORE_PREF) TYPE  CHAR1 OPTIONAL

*"     VALUE(I_DEST) TYPE  BU_RFCDEST DEFAULT 'NONE'

*"  CHANGING

*"     VALUE(C_DATA) TYPE  STRING

*"     VALUE(C_STRUCT) TYPE  STRING

*"----------------------------------------------------------------------

  type-pools: abap.

  data: ls_struct type dfies,

        lt_struct type standard table of dfies,

        lt_type type dd02v-tabclass,

        lt_component type cl_abap_structdescr=>component_table,

        ls_component like line of lt_component,

        lr_struct type ref to cl_abap_structdescr,

        l_ref type ref to data,

        l_len type i,

        l_intlen type i,

        l_decimals type i,

        lr_stru type ref to cl_abap_structdescr,

       lv_JSON type string,

      lx_JSON type xstring,

      lv_struct type string,

      lrd_struct type ref to data,

            lrd_data type ref to data,

                  lc_util type ref to zcl_bw_utility,

                  l_rc like sy-subrc .

  field-symbols: <lt_data> type standard table,

                 <ls_data> type any,

                 <ls_result> type any,

                 <lt_result> type standard table.

  if i_ind = 'S'. "server side

CALL FUNCTION 'VIEW_AUTHORITY_CHECK' “security check on the source system/server side
     EXPORTING
          VIEW_ACTION                    = 'S'
          VIEW_NAME                      = itab_name
     EXCEPTIONS
          NO_AUTHORITY                   = 2
          NO_CLIENTINDEPENDENT_AUTHORITY = 2
          NO_LINEDEPENDENT_AUTHORITY     = 2
          OTHERS                         = 1.

IF SY-SUBRC = 2.
  RAISE NOT_AUTHORIZED.

Return.
ELSEIF SY-SUBRC = 1.
  RAISE TABLE_NOT_AVAILABLE.

Return.
ENDIF.

    lr_stru ?= cl_abap_structdescr=>describe_by_name( p_name = itab_name ).

    create data l_ref type handle lr_stru.

    assign l_ref->* to <ls_data>.

    create data l_ref like table of <ls_data>.

    assign l_ref->* to <lt_data>.

    select * from (itab_name) into table <lt_data> .

    read table <lt_data> into <ls_data> index 1.

    lr_stru ?= cl_abap_structdescr=>describe_by_data( p_data = <ls_data> ).

    call function 'DDIF_FIELDINFO_GET'

      exporting

        tabname        = itab_name

*       FIELDNAME      = ' '

*       LANGU          = SY-LANGU

*       LFIELDNAME     = ' '

*       ALL_TYPES      = ' '

*       GROUP_NAMES    = ' '

*       UCLEN          =

*       DO_NOT_WRITE   = ' '

      importing

*       X030L_WA       =

        ddobjtype      = lt_type

*       DFIES_WA       =

*       LINES_DESCR    =

      tables

        dfies_tab      = lt_struct

*       FIXED_VALUES   =

      exceptions

        not_found      = 1

        internal_error = 2

        others         = 3.

    if sy-subrc <> 0.

* Implement suitable error handling here

    endif.

*  ct_struct = lt_struct.

 

 

    call method zcl_ui2_JSON=>serialize

      exporting

        data        = <lt_data>

        compress    = abap_true

*       name        =

        pretty_name = zcl_ui2_JSON=>pretty_mode-camel_case

*       type_descr  =

      receiving

        r_JSON      = c_data.

    call method zcl_ui2_JSON=>serialize

      exporting

        data        = lt_struct

        compress    = abap_true

*       name        =

        pretty_name = zcl_ui2_JSON=>pretty_mode-camel_case

*       type_descr  =

      receiving

        r_JSON      = c_struct.

  elseif i_ind = 'C'. "client side.

 

    call function 'Z_GET_TBLCNT' destination i_dest

      exporting

        itab_name = itab_name

        i_ind     = 'S'

      changing

        c_data    = lv_JSON

        c_struct  = lv_struct.

    lc_util = zcl_bw_utility=>get_instance( ).

    if i_store_pref = 'T'.

      try.

          call method zcl_ui2_JSON=>deserialize

            exporting

              JSON = lv_struct

*             pretty_name = PRETTY_MODE-NONE

            changing

              data = lt_struct.

        catch cx_sy_move_cast_error .

      endtry.

      get reference of lt_struct into lrd_struct.

 

 

      loop at lt_struct into ls_struct.

        ls_component-name = ls_struct-fieldname.

        move ls_struct-leng to l_len.

        move ls_struct-intlen to l_intlen.

        move ls_struct-decimals to l_decimals.

        case ls_struct-inttype.

          when cl_abap_elemdescr=>typekind_char.

            ls_component-type ?= cl_abap_elemdescr=>get_c( p_length = l_len ).

          when cl_abap_elemdescr=>typekind_packed.

            ls_component-type ?= cl_abap_elemdescr=>get_p( p_length = l_intlen p_decimals = l_decimals ).

          when cl_abap_elemdescr=>typekind_date.

            ls_component-type ?= cl_abap_elemdescr=>get_d( ).

          when cl_abap_elemdescr=>typekind_num.

            ls_component-type ?= cl_abap_elemdescr=>get_n( p_length = l_len ).

        endcase.

        append ls_component to lt_component.

      endloop.

      lr_struct = cl_abap_structdescr=>get( p_components = lt_component ).

 

      create data l_ref type handle lr_struct.

      assign l_ref->* to <ls_result>.

      create data l_ref like table of <ls_result>.

      assign l_ref->* to <lt_result>.

      try.

          call method zcl_ui2_JSON=>deserialize

            exporting

              JSON = lv_JSON

*             pretty_name = PRETTY_MODE-NONE

            changing

              data = <lt_result>.

        catch cx_sy_move_cast_error .

      endtry.

      get reference of <lt_result> into lrd_data.

      check  lc_util->put_data( i_tabname = itab_name i_cat = 'STRUCT' i_type = 'TABLE' i_data    = lrd_struct ) = 0.

      check  lc_util->put_data( i_tabname = itab_name i_cat = 'DATA' i_type = 'TABLE' i_data    = lrd_data ) = 0.

    elseif i_store_pref = 'S'.

*  keep it as string.

      get reference of lv_struct into lrd_struct.

      get reference of lv_JSON into lrd_data.

      check  lc_util->put_data( i_tabname = itab_name i_cat = 'STRUCT' i_type = 'STRING' i_data    = lrd_struct ) = 0.

      check  lc_util->put_data( i_tabname = itab_name i_cat = 'DATA' i_type = 'STRING' i_data    = lrd_data ) = 0.

    else.

*ERROR MESSAGE HERE

    endif.

  else.

*  ERROR MESSAGE.

  endif.

endfunction.

Figure 28
The content of function module Z_GET_TBLCNT

Figure 29 shows class ZCL_BW_UTILITY. This utility class helps to store and retrieve data, making data access independent of the main function of reading table content from any SAP system.


class ZCL_BW_UTILITY definition

  public

  final

  create public .

 

public section.

 

  types:

    begin of TS_DATA ,

    id type tabname,

    category type char6,

  l_type type char6,

  l_data type ref to data,

    end of ts_data .

  types:

    tt_data type hashed TABLE OF ts_data  with UNIQUE key id category l_type .

 

  data DT_DATA type TT_DATA .

 

  class-methods GET_INSTANCE

    returning

      value(R_INST) type ref to ZCL_BW_UTILITY .

  methods GET_DATA

    importing

      !I_TABNAME type TABNAME

      !I_CAT type CHAR6

      !I_TYPE type CHAR6

    returning

      value(E_DATA) type ref to DATA .

  methods PUT_DATA

    importing

      !I_TABNAME type TABNAME

      !I_CAT type CHAR6

      !I_TYPE type CHAR6

      !I_DATA type ref to DATA

    returning

      value(E_RC) type CHAR1 .

protected section.

private section.

 

  class-data M_REF type ref to ZCL_BW_UTILITY .

ENDCLASS.

 

 

 

CLASS ZCL_BW_UTILITY IMPLEMENTATION.

 

 

* <SIGNATURE>---------------------------------------------------------------------------------------+

* | Instance Public Method ZCL_BW_UTILITY->GET_DATA

* +-------------------------------------------------------------------------------------------------+

* | [--->] I_TABNAME                      TYPE        TABNAME

* | [--->] I_CAT                          TYPE        CHAR6

* | [--->] I_TYPE                         TYPE        CHAR6

* | [<-()] E_DATA                         TYPE REF TO DATA

* +--------------------------------------------------------------------------------------</SIGNATURE>

  method GET_DATA.

    data:

          ls_data type ts_data.

    READ TABLE dt_data into ls_data WITH TABLE KEY

    id = i_tabname

    category = i_cat

    l_type = i_type.

    if sy-subrc = 0.

      e_data = ls_data-l_data.

      endif.

  endmethod.

 

 

* <SIGNATURE>---------------------------------------------------------------------------------------+

* | Static Public Method ZCL_BW_UTILITY=>GET_INSTANCE

* +-------------------------------------------------------------------------------------------------+

* | [<-()] R_INST                         TYPE REF TO ZCL_BW_UTILITY

* +--------------------------------------------------------------------------------------</SIGNATURE>

  method GET_INSTANCE.

    if m_ref is INITIAL.

      create object m_ref.

    endif.

          r_inst = m_ref.

 

  endmethod.

 

 

* <SIGNATURE>---------------------------------------------------------------------------------------+

* | Instance Public Method ZCL_BW_UTILITY->PUT_DATA

* +-------------------------------------------------------------------------------------------------+

* | [--->] I_TABNAME                      TYPE        TABNAME

* | [--->] I_CAT                          TYPE        CHAR6

* | [--->] I_TYPE                         TYPE        CHAR6

* | [--->] I_DATA                         TYPE REF TO DATA

* | [<-()] E_RC                           TYPE        CHAR1

* +--------------------------------------------------------------------------------------</SIGNATURE>

  method PUT_DATA.

    data: ls_data type ts_data.

    read TABLE dt_data with TABLE KEY id = i_tabname

    category = i_cat

    l_type = i_type TRANSPORTING NO FIELDS.

    if sy-subrc ne 0 .

    ls_data-id = i_tabname.

    ls_data-category = i_cat.

    ls_data-l_type = i_type.

    ls_data-l_data = i_data.

    insert ls_data into TABLE dt_data.

    endif.

    e_rc = sy-subrc.

 

  endmethod.

ENDCLASS.

Figure 29
Class ZCL_BW_UTILITY

Figure 30 shows class ZCL_UI2_JSON. This is a local copy of class /ui2/cl_JSON from

http://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer as of 4/14/2015. The highlighted lines are not included in SDN. You have to add them.


Figure 30
Add these lines to the code

The source code is shown in Figure 31. This is the class to do the JSON XML <-> abap conversion.

:

*----------------------------------------------------------------------*
*       CLASS zcl_ui2_JSON DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
class zcl_ui2_JSON definition
    public
  final
  create public .
  public section.
    type-pools abap .
    class cx_sy_conversion_error definition load .
    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',
      end of  pretty_mode .
    class-data:
      sv_white_space type string read-only .
    class-methods:
      class_constructor,
      xstring_to_string importing in         type any
                        returning value(out) type string,
      string_to_xstring importing in         type string
                        changing  value(out) type any,
      restore           importing JSON        type string
                                  pretty_name type pretty_name_mode default pretty_mode-none
                                  length      type i
                        changing  data        type data optional
                                  offset      type i default 0
                        raising   cx_sy_move_cast_error,
      restore_type      importing JSON        type string
                                  pretty_name type pretty_name_mode default pretty_mode-none
                                  length      type i
                        changing  data        type data optional
                                  offset      type i default 0
                        raising   cx_sy_move_cast_error,
      dump              importing data          type data
                                  compress      type abap_bool default abap_false
                                  type_descr    type ref to cl_abap_typedescr optional
                                  pretty_name   type pretty_name_mode default pretty_mode-none
                        returning value(r_JSON) type string,
      deserialize       importing JSON        type string
                                  pretty_name type pretty_name_mode default pretty_mode-none
                        changing  data        type data
                        raising   cx_sy_move_cast_error,
      serialize         importing data          type data
                                  compress      type abap_bool default abap_false
                                  name          type string optional
                                  pretty_name   type pretty_name_mode default pretty_mode-none
                                  type_descr    type ref to cl_abap_typedescr optional
                        returning value(r_JSON) type string,
      pretty_name       importing in         type csequence
                        returning value(out) type string .
  PROTECTED SECTION.
    CONSTANTS mc_boolean_types TYPE string VALUE `\TYPE-POOL=ABAP\TYPE=ABAP_BOOL#\TYPE=BOOLEAN#\TYPE=BOOLE_D#\TYPE=XFELD`. "#EC NOTEXT
ENDCLASS.



CLASS ZCL_UI2_JSON IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_JSON=>CLASS_CONSTRUCTOR
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD class_constructor.
    sv_white_space = cl_abap_char_utilities=>get_simple_spaces_for_cur_cp( ).
  ENDMETHOD.                    "class_constructor


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_JSON=>DESERIALIZE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON                           TYPE        STRING
* | [--->] PRETTY_NAME                    TYPE        PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [<-->] DATA                           TYPE        DATA
* | [!CX!] CX_SY_MOVE_CAST_ERROR
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD deserialize.
    DATA: length    TYPE i,
          unescaped LIKE JSON.
    IF JSON IS NOT INITIAL.
      unescaped = JSON.
      " to eliminate numeric replacement calls for every single sting value, we do
      " replacement over all JSON text, while this shall not destroy JSON structure
      REPLACE ALL OCCURRENCES OF `\r\n` IN unescaped WITH cl_abap_char_utilities=>cr_lf.
      REPLACE ALL OCCURRENCES OF `\n`   IN unescaped WITH cl_abap_char_utilities=>newline.
      REPLACE ALL OCCURRENCES OF `\t`   IN unescaped WITH cl_abap_char_utilities=>horizontal_tab.
      length = numofchar( unescaped ).
      restore_type( EXPORTING JSON = unescaped pretty_name = pretty_name length = length CHANGING data = data ).
    ENDIF.
  ENDMETHOD.                    "deserialize


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_JSON=>DUMP
* +-------------------------------------------------------------------------------------------------+
* | [--->] DATA                           TYPE        DATA
* | [--->] COMPRESS                       TYPE        ABAP_BOOL (default =ABAP_FALSE)
* | [--->] TYPE_DESCR                     TYPE REF TO CL_ABAP_TYPEDESCR(optional)
* | [--->] PRETTY_NAME                    TYPE        PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [<-()] R_JSON                         TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD dump.
    DATA: l_typedesc         TYPE REF TO cl_abap_typedescr,
          l_elem_descr       TYPE REF TO cl_abap_elemdescr,
          properties         TYPE STANDARD TABLE OF string,
          fields             TYPE STANDARD TABLE OF string,
          symbol_table       TYPE cl_abap_structdescr=>symbol_table,
          lv_prop_name       TYPE string,
          lv_itemval         TYPE string.
    FIELD-SYMBOLS: <attr>             LIKE LINE OF cl_abap_objectdescr=>attributes,
                   <line>             TYPE any,
                   <value>            TYPE any,
                   <symbol_table>     LIKE LINE OF symbol_table,
                   <table>            TYPE ANY TABLE.
    " we need here macro instead of method calls because of the performance reasons.
    " Based on SAT measurments.
    "Loop attributes of class
    CASE type_descr->kind.
      WHEN cl_abap_typedescr=>kind_ref." OBJECT
        DATA: l_classdesc TYPE REF TO cl_abap_classdescr,
               obj_ref    TYPE REF TO object.
        IF data IS INITIAL.
          r_JSON = `null`.
        ELSE.
          obj_ref ?= data.
          l_classdesc ?= cl_abap_typedescr=>describe_by_object_ref( obj_ref ).
          LOOP AT l_classdesc->attributes ASSIGNING <attr> WHERE is_constant EQ abap_false AND alias_for IS INITIAL AND
            ( is_interface EQ abap_false OR type_kind NE cl_abap_typedescr=>typekind_oref ).
            ASSIGN obj_ref->(<attr>-name) TO <value>.
            IF compress EQ abap_false OR <value> IS NOT INITIAL.
              l_typedesc = cl_abap_typedescr=>describe_by_data( <value> ).
              lv_itemval = dump( data = <value> compress = compress pretty_name = pretty_name type_descr = l_typedesc ).
              format_name <attr>-name pretty_name lv_prop_name.
              CONCATENATE `"` lv_prop_name  `":` lv_itemval INTO lv_itemval.
              APPEND lv_itemval TO properties.
            ENDIF.
          ENDLOOP.
          CONCATENATE LINES OF properties INTO r_JSON SEPARATED BY `,`.
          CONCATENATE `{` r_JSON `}` INTO r_JSON.
        ENDIF.
      WHEN cl_abap_typedescr=>kind_elem. "if it is elementary type_descr add it to JSON
        l_elem_descr ?= type_descr.
        dump_type data l_elem_descr r_JSON.
      WHEN cl_abap_typedescr=>kind_struct."if it`s structure loop throught the components of structure
        DATA: l_structdesc TYPE REF TO cl_abap_structdescr.
        l_structdesc ?= type_descr.
        symbol_table = l_structdesc->get_symbols( ).
        LOOP AT symbol_table ASSIGNING <symbol_table>.
          ASSIGN COMPONENT <symbol_table>-name OF STRUCTURE data TO <value>.
          IF compress EQ abap_false OR <value> IS NOT INITIAL.
            lv_itemval = dump( data = <value> compress = compress pretty_name = pretty_name type_descr = <symbol_table>-type ).
            format_name <symbol_table>-name pretty_name lv_prop_name.
            CONCATENATE `"` lv_prop_name  `":` lv_itemval INTO lv_itemval.
            APPEND lv_itemval TO properties.
          ENDIF.
        ENDLOOP.
        CONCATENATE LINES OF properties INTO r_JSON SEPARATED BY `,`.
        CONCATENATE `{` r_JSON `}` INTO r_JSON.
      WHEN cl_abap_typedescr=>kind_table.
        DATA: l_tabledescr TYPE REF TO cl_abap_tabledescr.
        l_tabledescr ?= type_descr.
        l_typedesc = l_tabledescr->get_table_line_type( ).
        ASSIGN data TO <table>.
        " optimization for structured tables
        IF l_typedesc->kind EQ cl_abap_typedescr=>kind_struct.
          TYPES: BEGIN OF t_s_column,
                  header TYPE string,
                  name   TYPE string,
                  type   TYPE REF TO cl_abap_datadescr,
                 END OF t_s_column.
          DATA: columns TYPE STANDARD TABLE OF t_s_column.
          FIELD-SYMBOLS: <column> LIKE LINE OF columns.
          l_structdesc ?= l_typedesc.
          symbol_table = l_structdesc->get_symbols( ).
          LOOP AT symbol_table ASSIGNING <symbol_table>.
            APPEND INITIAL LINE TO columns ASSIGNING <column>.
            MOVE-CORRESPONDING <symbol_table> TO <column>.
            format_name <symbol_table>-name pretty_name <column>-header.
            CONCATENATE `"` <column>-header  `":` INTO <column>-header.
          ENDLOOP.
          LOOP AT <table> ASSIGNING <line>.
            CLEAR fields.
            LOOP AT columns ASSIGNING <column>.
              ASSIGN COMPONENT <column>-name OF STRUCTURE <line> TO <value>.
              IF compress EQ abap_false OR <value> IS NOT INITIAL.
                IF <column>-type->kind EQ cl_abap_typedescr=>kind_elem.
                  l_elem_descr ?= <column>-type.
                  dump_type <value> l_elem_descr lv_itemval.
                ELSE.
                  lv_itemval = dump( data = <value> compress = compress pretty_name = pretty_name type_descr = <column>-type ).
                ENDIF.
                CONCATENATE <column>-header lv_itemval INTO lv_itemval.
                APPEND lv_itemval TO fields.
              ENDIF.
            ENDLOOP.
            CONCATENATE LINES OF fields INTO lv_itemval SEPARATED BY `,`.
            CONCATENATE `{` lv_itemval `}` INTO lv_itemval.
            APPEND lv_itemval TO properties.
          ENDLOOP.
        ELSE.
          LOOP AT <table> ASSIGNING <value>.
            lv_itemval = dump( data = <value> compress = compress pretty_name = pretty_name type_descr = l_typedesc ).
            APPEND lv_itemval TO properties.
          ENDLOOP.
        ENDIF.
        CONCATENATE LINES OF properties INTO r_JSON SEPARATED BY `,`.
        CONCATENATE `[` r_JSON `]` INTO r_JSON.
    ENDCASE.
  ENDMETHOD.                    "dump


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_JSON=>PRETTY_NAME
* +-------------------------------------------------------------------------------------------------+
* | [--->] IN                             TYPE        CSEQUENCE
* | [<-()] OUT                            TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD pretty_name.
    DATA: tokens TYPE TABLE OF char128.
    FIELD-SYMBOLS: <token> LIKE LINE OF tokens.
    out = in.
    TRANSLATE out TO LOWER CASE.
    TRANSLATE out USING `/_:_~_`.
    SPLIT out AT `_` INTO TABLE tokens.
    DELETE tokens WHERE table_line IS INITIAL.
    LOOP AT tokens ASSIGNING <token> FROM 2.
      TRANSLATE <token>(1) TO UPPER CASE.
    ENDLOOP.
    CONCATENATE LINES OF tokens INTO out.
  ENDMETHOD.                    "pretty_name


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_JSON=>RESTORE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON                           TYPE        STRING
* | [--->] PRETTY_NAME                    TYPE        PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [--->] LENGTH                         TYPE        I
* | [<-->] 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,
          pos         LIKE offset,
          excp        TYPE REF TO cx_sy_move_cast_error,
          name_JSON   TYPE string,
          name_abap   TYPE string.
    FIELD-SYMBOLS: <value> TYPE any.
    eat_white.
    eat_char `{`.
    WHILE offset < length AND JSON+offset(1) NE `}`.
      eat_white.
      eat_string name_JSON.
      eat_white.
      eat_char `:`.
      eat_white.
      UNASSIGN <value>.
      name_abap = name_JSON.
      TRANSLATE name_abap TO UPPER CASE.
      ASSIGN COMPONENT name_abap OF STRUCTURE data TO <value>.
      IF <value> IS NOT ASSIGNED AND pretty_name EQ abap_true.
        name_abap = name_JSON.
        REPLACE ALL OCCURRENCES OF REGEX `([a-z])([A-Z])` IN name_abap WITH `$1_$2`. "#EC NOTEXT
        TRANSLATE name_abap TO UPPER CASE.
        ASSIGN COMPONENT name_abap OF STRUCTURE data TO <value>.
      ENDIF.
      IF <value> IS ASSIGNED.
        restore_type( EXPORTING JSON = JSON length = length pretty_name = pretty_name CHANGING data = <value> offset = offset ).
      ELSE.
        restore_type( EXPORTING JSON = JSON length = length pretty_name = pretty_name CHANGING offset = offset ).
      ENDIF.
      eat_white.
      IF offset < length AND JSON+offset(1) NE `}`.
        eat_char `,`.
      ELSE.
        EXIT.
      ENDIF.
    ENDWHILE.
    eat_char `}`.
  ENDMETHOD.                    "restore


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_JSON=>RESTORE_TYPE
* +-------------------------------------------------------------------------------------------------+
* | [--->] JSON                           TYPE        STRING
* | [--->] PRETTY_NAME                    TYPE        PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [--->] LENGTH                         TYPE        I
* | [<-->] 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
          pos         LIKE offset,
          line        TYPE REF TO data,
          elem_descr  TYPE REF TO cl_abap_elemdescr,
          type_descr  TYPE REF TO cl_abap_typedescr,
          table_descr TYPE REF TO cl_abap_tabledescr,
          excp        TYPE REF TO cx_sy_move_cast_error.
    FIELD-SYMBOLS: <line>           TYPE any,
                   <table>          TYPE ANY TABLE,
                   <table_sorted>   TYPE SORTED TABLE,
                   <table_hashed>   TYPE HASHED TABLE,
                   <table_standard> TYPE STANDARD TABLE.
    eat_white.
    CASE JSON+offset(1).
      WHEN `{`. " object
        IF data IS SUPPLIED.
          restore( EXPORTING JSON = JSON pretty_name = pretty_name length = length
                   CHANGING data = data offset = offset ).
        ELSE.
          restore( EXPORTING JSON = JSON pretty_name = pretty_name length = length
                   CHANGING  offset = offset ).
        ENDIF.
      WHEN `[`. " array
        eat_char `[`.
        eat_white.
        IF JSON+offset(1) NE `]`.
          type_descr = cl_abap_typedescr=>describe_by_data( data ).
          IF type_descr->type_kind EQ cl_abap_typedescr=>typekind_table.
            table_descr ?= type_descr.
            ASSIGN data TO <table>.
            CREATE DATA line LIKE LINE OF <table>.
            ASSIGN line->* TO <line>.
            WHILE offset < length AND JSON+offset(1) NE `]`.
              CLEAR <line>.
              restore_type( EXPORTING JSON = JSON length = length pretty_name = pretty_name CHANGING data = <line> offset = offset ).
              CASE table_descr->table_kind.
                WHEN cl_abap_tabledescr=>tablekind_sorted.
                  ASSIGN data TO <table_sorted>.
                  INSERT <line> INTO TABLE <table_sorted>.
                WHEN cl_abap_tabledescr=>tablekind_hashed.
                  ASSIGN data TO <table_hashed>.
                  INSERT <line> INTO TABLE <table_hashed>.
                WHEN OTHERS.
                  ASSIGN data TO <table_standard>.
                  APPEND <line> TO <table_standard>.
              ENDCASE.
              eat_white.
              IF offset < length AND JSON+offset(1) NE `]`.
                eat_char `,`.
              ELSE.
                EXIT.
              ENDIF.
            ENDWHILE.
          ELSE.
            WHILE offset < length AND JSON+offset(1) NE `}`.
              eat_white.
              restore_type( EXPORTING JSON = JSON length = length pretty_name = pretty_name CHANGING offset = offset ).
              IF offset < length AND JSON+offset(1) NE `]`.
                eat_char `,`.
              ELSE.
                EXIT.
              ENDIF.
            ENDWHILE.
          ENDIF.
        ENDIF.
        eat_char `]`.
      WHEN `"`. " string
        IF data IS SUPPLIED.
          eat_string sdummy.
          " unescape string
          IF sdummy IS NOT INITIAL.
            REPLACE ALL OCCURRENCES OF `\"` IN sdummy WITH `"`.
            REPLACE ALL OCCURRENCES OF `\\` IN sdummy WITH `\`.
            type_descr = cl_abap_typedescr=>describe_by_data( data ).
            IF type_descr->kind EQ cl_abap_typedescr=>kind_elem.
              elem_descr ?= type_descr.
              CASE elem_descr->type_kind.
                WHEN cl_abap_typedescr=>typekind_char.
                  IF elem_descr->output_length EQ 1 AND mc_boolean_types CS elem_descr->absolute_name.
                    IF sdummy(1) EQ `X` OR sdummy(1) EQ `t` OR sdummy(1) EQ `T` OR sdummy(1) EQ `x`.
                      data = abap_true.
                    ELSE.
                      data = abap_false.
                    ENDIF.
                    RETURN.
                  ENDIF.
                WHEN cl_abap_typedescr=>typekind_xstring OR cl_abap_typedescr=>typekind_hex.
                  string_to_xstring( EXPORTING in = sdummy CHANGING out = data ).
                  RETURN.
                WHEN cl_abap_typedescr=>typekind_date.
                  REPLACE FIRST OCCURRENCE OF REGEX `(\d{4})-(\d{2})-(\d{2})` IN sdummy WITH `$1$2$3`.
                WHEN cl_abap_typedescr=>typekind_time.
                  REPLACE FIRST OCCURRENCE OF REGEX `(\d{2}):(\d{2}):(\d{2})` IN sdummy WITH `$1$2$3`.
              ENDCASE.
            ENDIF.
          ENDIF.
          MOVE sdummy TO data. " to avoid crashes due to data type inconsistency
        ELSE.
          eat_string sdummy.
        ENDIF.
      WHEN `-`. " number
        IF data IS SUPPLIED.
          eat_number data.
        ELSE.
          eat_number sdummy.
        ENDIF.
      WHEN OTHERS.
        FIND FIRST OCCURRENCE OF JSON+offset(1) IN `0123456789`.
        IF sy-subrc IS INITIAL. " number
          IF data IS SUPPLIED.
            eat_number data.
          ELSE.
            eat_number sdummy.
          ENDIF.
        ELSE. " true/false/null
          IF data IS SUPPLIED.
            eat_bool data.
          ELSE.
            eat_bool sdummy.
          ENDIF.
        ENDIF.
    ENDCASE.
  ENDMETHOD.                    "restore_type


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_JSON=>SERIALIZE
* +-------------------------------------------------------------------------------------------------+
* | [--->] DATA                           TYPE        DATA
* | [--->] COMPRESS                       TYPE        ABAP_BOOL (default =ABAP_FALSE)
* | [--->] NAME                           TYPE        STRING(optional)
* | [--->] PRETTY_NAME                    TYPE        PRETTY_NAME_MODE (default =PRETTY_MODE-NONE)
* | [--->] TYPE_DESCR                     TYPE REF TO CL_ABAP_TYPEDESCR(optional)
* | [<-()] R_JSON                         TYPE        STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD serialize.
    DATA: lrf_descr TYPE REF TO cl_abap_typedescr.
    IF type_descr IS INITIAL.
      lrf_descr = cl_abap_typedescr=>describe_by_data( data ).
    ELSE.
      lrf_descr = type_descr.
    ENDIF.
    r_JSON = dump( data = data compress = compress pretty_name = pretty_name type_descr = lrf_descr ).
    " we do not do escaping of every single string value for white space characters,
    " but we do it on top, to replace multiple calls by 3 only, while we do not serialize
    " outlined/formatted JSON this shall not produce any harm
    REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>cr_lf          IN r_JSON WITH `\r\n`.
    REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>newline        IN r_JSON WITH `\n`.
    REPLACE ALL OCCURRENCES OF cl_abap_char_utilities=>horizontal_tab IN r_JSON WITH `\t`.
    IF name IS NOT INITIAL AND ( compress EQ abap_false OR r_JSON IS NOT INITIAL ).
      CONCATENATE `"` name `":` r_JSON INTO r_JSON.
    ENDIF.
  ENDMETHOD.                    "serialize


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_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  = 99.
    IF sy-subrc IS INITIAL.
      MOVE lv_xstring TO out.
    ELSE.
      MOVE in TO out.
    ENDIF.
  ENDMETHOD.                    "string_to_xstring


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UI2_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  = 99.
    IF sy-subrc IS NOT INITIAL.
      MOVE in TO out.
    ENDIF.
  ENDMETHOD.                    "xstring_to_string
ENDCLASS.

Figure 31
The code for the class to do the JSON XML <-> ABAP conversion

An email has been sent to:





 

George Chen

George Chen is the owner of Lynk, Inc. An SAP consultant, he has worked on SAP Netweaver ABAP/HANA/BPC/BW/IP/TPM/CRM for the past 17 years. He specializes in process integration, performance tuning, and introducing advanced ABAP design patterns in development. He has worked with SAP America many times to conduct ABAP performance tuning and troubleshooting. His focuses are ABAP for HANA and ABAP OO in SAP NetWeaver.



More from SAPinsider



COMMENTS

Please log in to post a comment.

No comments have been submitted on this article. Be the first to comment!


SAPinsider
FAQ