Get Data From Any Table in Another SAP System

Get Data From Any Table in Another SAP System

A Generic Way in ABAP

Published: 02/July/2015

Reading time: 18 mins

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: https://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

 

https://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=ABAPTYPE=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 `rn` 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 `rn`.
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


More Resources

See All Related Content