Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
fatihpense
Active Contributor

Hi ABAP developers,


Update 2021-07-11: After 5 years, to my surprise, this library is still useful for some edge cases. I couldn't support fixing regex bugs(Because they are impossible to fix without introducing new bugs). Now there is a new library with the same methods, which doesn't use regex for parsing JSON. It is just a bit slower but doesn't contain parsing bugs. You can find it here: https://github.com/fatihpense/abap-tasty-json

I would like to introduce a new open-source ABAP JSON library we have developed. Why the world needs a new JSON library? I will explain our rationale behind developing this library with its features. In the end it is about having more choices and knowing trade-offs. I would like to thank MDP IT Consulting for letting this work become open-source with the MIT License.


Table of Contents:




  • Summary

  • Alternatives

  • Reasoning and features

  • Examples

  • Performance

  • Links

  • Warning

  • Conclusion


Summary


You can generate any custom JSON with this library unlike alternatives. Thus you can easily achieve API compatibility with another JSON server written in another language. Beside providing a serializer and a deserializer, this library defines an intermediate JSON class in ABAP. Further development may enable more JSON utilities based on this JSON representation.



Alternatives


CL_TREX_JSON_*


Standard transformation using JSON-XML:  https://scn.sap.com/community/abap/blog/2013/01/07/abap-and-json


Manual string manipulation: While it provides flexibility, it is tedious and error prone work. Sometimes it is used together with CL_TREX_JSON_*


These libraries also seek automatic mapping:


https://github.com/se38/zJSON/wiki/Usage-zJSON


https://wiki.scn.sap.com/wiki/display/Snippets/One+more+ABAP+to+JSON+Serializer+and+Deserializer



Reasoning and features


It is intriguing to me that there was no JSON node representation in ABAP. Let me give examples from other languages:


Working with JSON in dynamic or loosely typed languages is easier since easily modifiable representations for JSON object and array already exists in the standard language:




In strongly typed languages like ABAP, Java, Go there are two approaches:




Our library has chosen the intermediary representation approach defining the class ZCL_MDP_JSON_NODE.




Features:



  • It provides flexibility down to JSON spec. This is important because you get the same flexibility as manual string manipulation without errors. So compatibility of your ABAP service or client with any other JSON API becomes possible without string manipulation.

  • You can deserialize any JSON string.

  • You can know exactly what deserializer will produce when you see a JSON string.

  • You don't need to define intermediary data types just for JSON input/output.


Future ideas for development:



  • Intermediary ZCL_MDP_JSON_NODE class enables development of methods like JSON equality checker, beautification of JSON output, checks for spec validity for string and number values.



  • The library uses regexes for parsing. Most of the time regex can be a quick solution. However, I think finite-state machines are better suited for parsers in general.



  • We will work on this library based on our needs and your suggestions. For example, we can work towards 100% compliance with the JSON specification running edge case tests.


Examples


Examples here are in the shortest form to show how easy JSON manipulation can become. There will be more examples at the project repo using other features of the class. JSON node class is easy to understand if you study attributes and methods once.



Deserialization Example:


DATA:  l_json_string TYPE STRING.

CONCATENATE

'{'

' "books": ['

' {'

' "title_original": "Kürk Mantolu Madonna",'

' "title_english": "Madonna in a Fur Coat",'

' "author": "Sabahattin Ali",'

' "quote_english": "It is, perhaps, easier to dismiss a man whose face gives no indication of an inner life. And what a pity that is: a dash of curiosity is all it takes to stumble upon treasures we never expected.",'

' "original_language": "tr"'

' },'

' {'

' "title_original": "Записки из подполья",'

' "title_english": "Notes from Underground",'

' "author": "Fyodor Dostoyevsky",'

' "quote_english": "I am alone, I thought, and they are everybody.",'

' "original_language": "ru"'

' },'

' {'

' "title_original": "Die Leiden des jungen Werthers",'

' "title_english": "The Sorrows of Young Werther",'

' "author": "Johann Wolfgang von Goethe",'

' "quote_english": "The human race is a monotonous affair. Most people spend the greatest part of their time working in order to live, and what little freedom remains so fills them with fear that they seek out any and every means to be rid of it.",'

' "original_language": "de"'

' },'

' {'

' "title_original": "The Call of the Wild",'

' "title_english": "The Call of the Wild",'

' "author": "Jack London",'

' "quote_english": "A man with a club is a law-maker, a man to be obeyed, but not necessarily conciliated.",'

' "original_language": "en"'

' }'

' ]'

'}'

INTO l_json_string

SEPARATED BY cl_abap_char_utilities=>cr_lf .

DATA: l_json_root_object TYPE REF TO zcl_mdp_json_node.

l_json_root_object = zcl_mdp_json_node=>deserialize( json = l_json_string ).

DATA: l_string TYPE STRING.

l_string = l_json_root_object->object_get_child_node( KEY = 'books'

)->array_get_child_node( INDEX = 1

)->object_get_child_node( KEY = 'quote_english' )->VALUE.

START-OF-SELECTION.

WRITE: 'Quote from the first book: ', l_string .

Serialization Example:


DATA: l_string_1 TYPE STRING.

DATA: l_root_object_node TYPE REF TO zcl_mdp_json_node

,l_books_array_node TYPE REF TO zcl_mdp_json_node

,l_book_object_node TYPE REF TO zcl_mdp_json_node

,l_book_attr_string_node TYPE REF TO zcl_mdp_json_node .

*Create root object

l_root_object_node = zcl_mdp_json_node=>create_object_node( ).

*Create books array

l_books_array_node =  zcl_mdp_json_node=>create_array_node( ).

*add books array to root object with key "books"

l_root_object_node->object_add_child_node( child_key = 'books'  child_node = l_books_array_node ).

*You would probably want to do this in a loop.

*Create book object node

l_book_object_node = zcl_mdp_json_node=>create_object_node( ).

*Add book object to books array

l_books_array_node->array_add_child_node( l_book_object_node ).

l_book_attr_string_node = zcl_mdp_json_node=>create_string_node( ).

l_book_attr_string_node->VALUE = 'Kürk Mantolu Madonna'.

*Add string to book object with key "title_original"

l_book_object_node->object_add_child_node( child_key = 'title_original' child_node = l_book_attr_string_node ).

l_string_1 = l_root_object_node->serialize( ).

*ALTERNATIVE:

DATA: l_string_2 TYPE STRING.

*DATA: l_root_object_node_2 type zcl_mdp_json_node.

*Create same JSON object with one dot(.) and without data definitions using chaining.

l_string_2 = zcl_mdp_json_node=>create_object_node(

)->object_add_child_node( child_key = 'books' child_node = zcl_mdp_json_node=>create_array_node(

)->array_add_child_node( child_node = zcl_mdp_json_node=>create_object_node(

)->object_add_child_node( child_key = 'title_original' child_node = zcl_mdp_json_node=>create_string_node(

)->string_set_value( VALUE = 'Kürk Mantolu Madonna' )

)

)

)->serialize( ).

START-OF-SELECTION.

WRITE: / 'string 1: ' , l_string_1.

WRITE: / 'string 2: ' , l_string_2.

Challenge: Try doing these examples with CL_TREX_JSON_*


For more examples please visit GitHub repo.



Performance


On a test machine, using JSON string example above(l_json_string) deserializing and serializing again 10000 times takes 2.1 seconds on average. It shouldn't have any performance problems with general usage. Complete benchmark code will be on the project repo.


DO 10000 TIMES.

zcl_mdp_json_deserializer=>deserialize(

EXPORTING json = l_json_string

IMPORTING node = l_jsonnode ).

zcl_mdp_json_serializer=>serialize(

EXPORTING node = l_jsonnode

IMPORTING json = l_json_string ).

ENDDO.

Links


Here is a presentation about this JSON library:


Medepia ABAP JSON Library ZCL_MDP_JSON


Project code repository:


GitHub - fatihpense/zcl_mdp_json: MDP ABAP JSON library that can generate and parse any JSON string.


Warning


The library isn't extensively battle tested as of now. Testing your use case before using it in production is strongly advised. Please report if you encounter any bugs.



Conclusion


If you are just exposing a table as JSON without much modification, it is easier and probably better to use CL_TREX_JSON_*


If you are developing an extensive application and if you want to design your API beautifully, this library is a pleasant option for you.


Thanks for reading.


Best wishes,


Fatih Pense



39 Comments