Introduction:
ABAP to JSON conversion is very common requirement now-a-days. This can be done easily using the standard class “/UI2/CL_JSON”. This is the best way to convert ABAP to JSON. There are already couples of blog post already there.
Problem Statement:
As mentioned already, “/UI2/CL_JSON” class is really handy and probably the best way to deal with “ABAP to JSON” conversion. But, recently I came across a requirement to convert ABAP to JSON format but the class “/UI2/CL_JSON” was not present in the system due its current patch level(below screenshot for reference). So, I came up with the idea of utilization of “Custom Transformation” and “custom class” for ABAP to JSON conversion and thought to share it so that it will be helpful for some one.
So in this blog post we will discuss regarding the ABAP to JSON conversion using custom class and if you have “/UI2/CL_JSON” in the system, you can leave this blog post here and follow the the standard class(links to blog post given above).
Note: Apart from “/UI2/CL_JSON”, we do have another standard class “CL_SXML_STRING_WRITER” and a standard transformation “ID” for ABAP to JSON conversion.We do have a very nice blog post regarding the same. Below is the link.
But, the “PRETTY_MODE” option is not available in this, which is available in “/UI2/CL_ABAP” class in the method “SERIALIZE”. Hence, the case of the “attribute” name in the converted JSON will be always in “UPPER CASE”.To translate it into camel case or lower case, I came up with idea to create a custom class to serve the purpose.
Proposed Solution:
If you are still with me, I assume you have to come up with the custom class for ABAP to JSON Conversion. Here are the tasks we will follow in this blog post to create our own solution.
◈ Creation of custom class “ZCL_JSON_UTILITY” which will be used to convert ABAP to JSON. ◈ This class will have below methods:
◈ Convert ABAP structure to JSON format
◈ Convert ABAP ITAB to JSON format
◈ Creation of custom transformation for conversion of attribute case of JSON
◈ A custom program using the class “ZCL_JSON_UTILITY” to show the ABAP to JSON conversion
So, lets start!
Step 1: Creation of class “ZCL_JSON_UTILITY”
Let’s create the class “ZCL_JSON_UTILITY” in class builder(t-code – SE24).
Below constants are defined so that the attribute of the JSON can be formatted with correct case(as we have “PRETTY_NAME” parameter in the “SERIALIZE” method of class “/UI2/CL_JSON”.
We will have 3 method in this class. Each one we will discussed in details.
◈ CONVERT_STUCT_TO_JSON
◈ CONVERT_ITAB_TO_JSON
◈ CONVERT_FNAME_CASE
Step 2: Creation of method – CONVERT_STUCT_TO_JSON
Let’s create a method “CONVERT_STUCT_TO_JSON”. Below is the screenshot of method signature.
In this method, we will convert the structure to JSON data. So, in this method we will do the following things
◈ Call the standard transformation “ID” to convert structure to JSON format. The data will be in XSTRING format. If we convert it to string, we can see the JSON data. But, the attribute will be in “UPPER CASE”.
◈ Pass the converted JSON data to the custom transformation “ZJSON_XML_TO_DIFF_CASE” to convert it into the required case. We will discuss regarding this transformation soon.
◈ Once the data is transformed as per the previous point, we will receive the converted JSON in xstring format. To convert it into string format, “CONVERT_FROM” method is used of the class “CL_ABAP_CODEPAGE”. There you go. You are done with the conversion. As simple as that.
Source code of the method:
DATA:
lo_string_writer TYPE REF TO cl_sxml_string_writer.
DATA:
lv_data TYPE xstring,
lv_arr_textin TYPE string,
lv_arr_textot TYPE string,
lv_len TYPE i.
TRY.
"Create string writer for JSON
lo_string_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
"Call transformation
CALL TRANSFORMATION id SOURCE structure = im_s_data RESULT XML lo_string_writer.
lv_data = lo_string_writer->get_output( ).
FREE lo_string_writer.
"Create string writer for JSON
lo_string_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
"Call transformation
CALL TRANSFORMATION zjson_xml_to_diff_case
PARAMETERS mode = im_v_case
SOURCE XML lv_data
RESULT XML lo_string_writer.
"Get JSON in string format
rt_v_json = cl_abap_codepage=>convert_from( lo_string_writer->get_output( ) ).
lv_arr_textin = 'structure'.
zcl_json_utility=>convert_fname_case(
EXPORTING
im_v_fname = lv_arr_textin
im_v_case = |{ im_v_case }|
RECEIVING
rt_v_fname = lv_arr_textot
).
IF rt_v_json CS lv_arr_textot.
lv_arr_textot = `{"` && lv_arr_textot && '":'.
REPLACE FIRST OCCURRENCE OF lv_arr_textot IN rt_v_json WITH ''.
lv_len = strlen( rt_v_json ) - 1.
IF lv_len GT 0.
rt_v_json = rt_v_json+0(lv_len).
ENDIF.
ENDIF.
CATCH cx_root.
RAISE EXCEPTION TYPE zcx_json_conversion_error.
ENDTRY.
Step 3: Creation of method – CONVERT_ITAB_TO_JSON
In this method, we have to convert ITAB data to JSON format. The same task are performed in this.
Below is the screenshot of the signature.
The task we followed in the previous step, similarly we have to do the thing in this method too. Below is the complete source code.
Source code of the method:
DATA:
lo_string_writer TYPE REF TO cl_sxml_string_writer.
DATA:
lv_data TYPE xstring,
lv_arr_textin TYPE string,
lv_arr_textot TYPE string,
lv_len TYPE i.
TRY.
"Create string writer for JSON
lo_string_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
"Call transformation
CALL TRANSFORMATION id SOURCE array = im_t_table RESULT XML lo_string_writer.
lv_data = lo_string_writer->get_output( ).
FREE lo_string_writer.
"Create string writer for JSON
lo_string_writer = cl_sxml_string_writer=>create( type = if_sxml=>co_xt_json ).
"Call transformation
CALL TRANSFORMATION zjson_xml_to_diff_case
PARAMETERS mode = im_v_case
SOURCE XML lv_data
RESULT XML lo_string_writer.
"Get JSON
rt_v_json = cl_abap_codepage=>convert_from( lo_string_writer->get_output( ) ).
lv_arr_textin = 'Array'.
zcl_json_utility=>convert_fname_case(
EXPORTING
im_v_fname = lv_arr_textin
im_v_case = |{ im_v_case }|
RECEIVING
rt_v_fname = lv_arr_textot
).
IF rt_v_json CS lv_arr_textot.
lv_arr_textot = `{"` && lv_arr_textot && '":'.
REPLACE FIRST OCCURRENCE OF lv_arr_textot IN rt_v_json WITH ''.
lv_len = strlen( rt_v_json ) - 1.
IF lv_len GT 0.
rt_v_json = rt_v_json+0(lv_len).
ENDIF.
ENDIF.
CATCH cx_root.
RAISE EXCEPTION TYPE zcx_json_conversion_error.
ENDTRY.
Step 4: Creation of method – CONVERT_FNAME_CASE
This method will convert the case of the attribute to different cases.This method is called in the custom transformation “ZJSON_XML_TO_DIFF_CASE” to translate the case of the attribute to required case.
The logic of this method is very simple. Hence, not covering the same in details.
Below is the complete source code
Source code of the method:
DATA:
lv_str TYPE string.
CLEAR rt_v_fname.
CHECK im_v_fname IS NOT INITIAL.
CASE im_v_case.
WHEN co_ftype_lowercase.
rt_v_fname = to_lower( im_v_fname ).
WHEN co_ftype_uppercase.
rt_v_fname = to_upper( im_v_fname ).
WHEN co_ftype_camelcase_upper.
lv_str = to_mixed( im_v_fname ).
rt_v_fname = to_upper( im_v_fname(1) ) && lv_str+1.
WHEN co_ftype_camelcase.
lv_str = to_mixed( im_v_fname ).
rt_v_fname = to_lower( im_v_fname(1) ) && lv_str+1.
ENDCASE.
REPLACE all OCCURRENCES OF '"' in rt_v_fname WITH ''.
Step 5: Creation of Custom Transformation “ZJSON_XML_TO_DIFF_CASE”
We have to create a custom transformation with the provided name in t-code “XSLT_TOOL”. The transformation type will “X – XSLT Program”.
Below is the code written in XSLT transformation. You can see the method “CONVERT_FNAME_CASE” is called to transform the case of the attribute name to different case.
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sap="http://www.sap.com/sapxsl" xmlns:f="FCT" exclude-result-prefixes="f" version="1.0">
<sap:external-function class="ZCL_JSON_UTILITY" kind="class" method="CONVERT_FNAME_CASE" name="f:toCC">
<sap:argument param="IM_V_FNAME" type="string"/>
<sap:argument param="IM_V_CASE" type="string"/>
<sap:result param="RT_V_FNAME" type="string"/>
</sap:external-function>
<xsl:param name="MODE"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="name">
<xsl:value-of select="f: toCC( string( . ), string( $MODE ) )"/>
</xsl:attribute>
</xsl:template>
</xsl:transform>
Step 6: Creation of exception class “ZCX_JSON_CONVERSION_ERROR” used in the method described in Step 2 and 3.
Below is the screenshot of exception class created for JSON conversion error.
Step 7: Creation of program “ZABAP_2_JSON” ABAP to JSON using the custom class created above.
Below is the source code of the program to convert ABAP to JSON using custom class. Different values been passed to the parameter “IM_V_CASE” of the method and the attribute name is translated accordingly in JSON.
REPORT zabap_2_json.
DATA:
BEGIN OF ls_data,
material_no TYPE mara-matnr,
material_desc TYPE string,
END OF ls_data,
lt_data LIKE TABLE OF ls_data INITIAL SIZE 0.
DATA:
lv_text TYPE string.
TRY.
ls_data-material_no = '900'.
ls_data-material_desc = 'Material 1'.
cl_demo_output=>begin_section( `Structure to JSON(Camel case):`).
zcl_json_utility=>convert_stuct_to_json(
EXPORTING
im_s_data = ls_data
im_v_case = zcl_json_utility=>co_ftype_camelcase
RECEIVING
rt_v_json = lv_text
).
cl_demo_output=>write( data = lv_text ).
cl_demo_output=>end_section( ).
cl_demo_output=>begin_section( `Structure to JSON(Camel case upper):` ).
zcl_json_utility=>convert_stuct_to_json(
EXPORTING
im_s_data = ls_data
im_v_case = zcl_json_utility=>co_ftype_camelcase_upper
RECEIVING
rt_v_json = lv_text
).
cl_demo_output=>write( data = lv_text ).
cl_demo_output=>end_section( ).
cl_demo_output=>begin_section( `Structure to JSON(lower case):` ).
zcl_json_utility=>convert_stuct_to_json(
EXPORTING
im_s_data = ls_data
im_v_case = zcl_json_utility=>co_ftype_lowercase
RECEIVING
rt_v_json = lv_text
).
cl_demo_output=>write( data = lv_text ).
cl_demo_output=>end_section( ).
cl_demo_output=>begin_section( `Structure to JSON(upper case):` ).
zcl_json_utility=>convert_stuct_to_json(
EXPORTING
im_s_data = ls_data
im_v_case = zcl_json_utility=>co_ftype_uppercase
RECEIVING
rt_v_json = lv_text
).
cl_demo_output=>write( data = lv_text ).
cl_demo_output=>end_section( ).
ls_data-material_no = '900'.
ls_data-material_desc = 'Material 1'.
APPEND ls_data TO lt_data.
ls_data-material_no = '901'.
ls_data-material_desc = 'Material 2'.
APPEND ls_data TO lt_data.
cl_demo_output=>begin_section( `ITAB to JSON(camel case):` ).
zcl_json_utility=>convert_itab_to_json(
EXPORTING
im_t_table = lt_data
im_v_case = zcl_json_utility=>co_ftype_camelcase
RECEIVING
rt_v_json = lv_text
).
cl_demo_output=>write( data = lv_text ).
cl_demo_output=>end_section( ).
cl_demo_output=>display( ).
CATCH zcx_json_conversion_error. " Error during JSON Conversion
ENDTRY.
Output of the program:
Do you need a case which is not in this program? Go to the step 4 and change the logic and populate “RT_V_FNAME” as per the format you need. Your purpose will be solved.
No comments:
Post a Comment