Technical Articles
ABAP to JSON Conversion
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. Below are the few links:-
https://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer
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.
Also, this blog post will be helpful if someone tries to understand on the available option to convert ABAP to JSON. As this post is based on custom class development for the conversion, it can give ideas on all the steps been involved in the process.
If you are looking for JSON to ABAP conversion using custom class, please refer here.
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.
https://blogs.sap.com/2013/01/07/abap-and-json/
But, the “PRETTY_MODE” option is not available in this, which is available in “/UI2/CL_JSON” 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.
Conclusion:
So, in this blog post, we have converted the ABAP to JSON data using the custom class. Hope this will helpful for someone if “/UI2/CL_ABAP” class is not available in the system.
Cheers!
I have to admit that unnecessary dashes in "now-a-days" initially triggered my OCD 🙂 but am willing to overlook that and even the use of Hungarian notation in the code because otherwise it's actually a really good blog.
It starts very nicely with an explanation of the use case and links to other blogs. This sets the scene perfectly for the readers. It offers the task overview and then explains the specific steps. The code is well-formatted, text is neat, clear, and the thought process is easy to follow.
Others might have some input regarding the ABAP code (especially with regards to Clean Code) but, as far as the blog itself goes, this is an example of what a good technical article should look like.
Well done and keep writing!
Thanks Jelena for the suggestions. Point noted and will keep these points in mind for future blog posts.
I am glad you liked the blog post.
Thanks,
Gourab
nice information Gourab Dey and its very helpfull for me
Digital Transformation
Thank you Anusha. I am glad it's helpful to you.
Thanks, very useful since i am in the situation "helpful for someone if “/UI2/CL_ABAP” class is not available" 🙂
I am glad it helped you.
I have to say that this blog is a very good blog. Thank you very much, this blog has been very very useful to me, thank you again.
Thanks Harvey. I am happy it helped you.
Excellent, Entry. But, How can I used it to JSON TO ABAP?.
JSON to ABAP is pretty straight forward. Use "deserialize" method of the class "/UI2/CL_JSON" if available in your system. Else, follow the below blog for conversion from JSON to ABAP.
https://blogs.sap.com/2013/01/07/abap-and-json/
Could you please help me with boolean conversion from abap to json. Thanks.
What do you mean by boolean conversion? Also, are you using the standard class "/UI2/CL_JSON" or custom transformation as shown in the current blog post?
Dear Gourab
Very nice presentation and Thanks for the blog.
Regards,
Venkat
Thanks Venkateswaran for your words.
can I use Odata project to convert internal table data to Json? Which one is easy approach between Odata project and what you have mentioned here?
If you have OData available in the system, then proceed with OData.
Dear Gourab,
very helpfull blog.
how can we avoid the quotation marks on integer fields in the json file?
thanks on advanced.