You are on page 1of 47

BGS Consulting ApS

Krmindevej 3
3500 Vrlse
Danmark

JSON parser for ABAP


Context
JSON parser for ABAP developed on SAP Netweaver release 7.0.

What is a JSON Parser for ABAP.


JSON or JavaScript Object Notation, is a lightweight text-based open standard designed for
human-readable data interchange. It is derived from the JavaScript scripting language for
representing simple data structures and associative arrays, called objects. Despite its
relationship to JavaScript, it is language-independent, with parsers available for many
languages. The JSON parser for ABAP is a class in ABAP that is able to interpret JSON and
return ABAP Data and vice versa. With JSON parser for ABAP you then can support
RESTful web services as integration with SAP.

Why is JSON interesting for ABAP developers.


JSON is interesting for ABAP developers, because JSON with BSP (Business Server Pages)
allow simple exposure of data from SAP to the Internet, without the use of SOA and the
administration that follows. From ABAP you could also call web services on the internet, that
return JSON as result. Nearly every web developer knows the JSON format, web tools and
programming languages support JSON directly in the runtime environment.
By using BSP and ICF services, we are able to provide URI/URL for the web developer, that
can be assigned to classes or functions within SAP. Hereby we are able to deliver any data
from SAP or receive any data to SAP, that any ABAP developer can work with, using well
known tools like RFC function modules or ABAP classes.
If we build a REST service, within ABAP that hide special HTTP issues from the ABAP
developer, and hide special SAP knowledge from the Web developer, we will be able to
expose any SAP data on the internet or on any mobile devices, that can be used by any kind
of web solution, whether nor using SAP web tools like Web Dynpro, Portal, ITS and similar.
The only piece missing, is some kind of utility that can serialize ABAP data to JSON
or deserialize JSON data to ABAP data. This missing link, is what this article is
about. The REST service will be explained and described in a later article.
On SDN http://www.sdn.sap.com/ you can read other articles and source code, that
address the same issue. I have been using several of these solutions, but found they
were too performance demanding, or was missing the deserialize function. Therefore
I spend some time to figure out another way of serializing and deserializing.

What is the benefit for you...


The article explain some of the choises in the solution,
The article show you the code behind the JSON parser within ABAP,
Udskrevet: 05-09-2013

Side 1 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

You can use this solution as inspiration for other types of issues, where you need
to work with dynamic structured complex data,
The class support the JSON format entirely, as describe at http://www.JSON.org
with very few exceptions.

What you should know...

You need to be an experienced ABAP developer,


You need some skils and knowledge about ABAP objects,
You should have an idea of what object design pattern is,
You should be familar with recursive calls,
You should have some understanding for web developments,
You must read about JSON at http:///www.json.org.

Introduction to JSON
JSON or JavaScript Object Notation, is a lightweight text-based open standard designed for
human-readable data interchange. It is derived from the JavaScript scripting language for
representing simple data structures and associative arrays, called objects. Despite its
relationship to JavaScript, it is language-independent, with parsers available for many
languages.
The official internet media type for JSON is application/JSON. The JSON filename extension
is .JSON.
The JSON format is often used for serializing and transmitting structured data over a network
connection. It is used primarily to transmit data between a server and web application,
serving as an alternative to XML.
For more information see http://www.JSON.org or other websites.

JSON Validator
When working with interpreter or compilers like the JSON parser for ABAP, it's important to
have a tool that you trust and that can check the JSON syntax. Several web services offer
syntax checkers like http://JSONlint.com which is the one I prefer.
Using a JSON validator, you are able to play around with JSON before after
serialize/deserialize checking the results from the serialize method and ensure the right
syntax for your input to the deserializer method.

Udskrevet: 05-09-2013

Side 2 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Figur 1 JSON Validator

The JSONLint Validator is a simple web editor where you fill in your JSON script, hit the
Validate button and get the result: valid JSON or a list of errors in the script.

JSON Notation implementation in ABAP


The JSON notation is simple as it only contains 5 elements object, array, value, string and
number. Here we look into the 5 elements implementation.
Before looking into the final implementation within the ABAP class, let's have a closer look
at the JSON notation Syntax by looking into these 5 elements. Here we look into the issues
where JSON and ABAP have different notations.
As we in ABAP must use ABAP known data type, the JSON Parser for ABAP, build upon the
assumption, that we in ABAP is familiar with the data type, structure, table etc, that we are
able to send or receive as JSON.
In the following we walk trough the JSON notation looking for issues in regards to the
implementation in ABAP.
Udskrevet: 05-09-2013

Side 3 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Object

Figur 2 JSON Object

In JSON an object is an unordered set of name/value pairs. An object begins with { (left brace)
and ends with } (right brace). Each name is followed by : (colon) and the name/value pairs are
separated by , (comma).
The equivalent data structure in ABAP, is a data structure comprising one or more fields. A
data structure is usually fixed, defined in the program or in the data dictionary. It is possible
to dynamically define the data structure in your program, but it means that the transmitter of a
JSON object, must send meta data describing the data structure. Metadata is not part of this
JSON solution, and thus the data structure used, is fixed in ABAP or Data dictionary.
If using a single field also called scalar field, it does not matter which field name is specified
as field name is not used for scalar fields in inbound mode, but in outbound mode you or at
least the web developer would like you to provide relevant fieldname, therefore the serialize
method provide the possibility to pass the object name. If you do not pass an object name the
method will name the scalar field after it's type.
For structures the fieldnames within ABAP must be the same as used in JSON,
otherwise you get a format error message. The deserialize function depend on the
fieldname. The JSON class however support the use of simple variables (scalar
fields) instead of structures, if and only if you only send one variable.
If you need to facilitate a collection of scalar fields, you must create a data structure
with the scalar fields in ABAP.
<<LISTING 1 >>
Listing 1: Code example for simple data structure
TYPES:
BEGIN OF ty_sflight
,mandt
TYPE
,carrid
TYPE
,connid
TYPE
,fldate
TYPE
,price
TYPE
,currency
TYPE
,planetype
TYPE
,seatsmax
TYPE
,seatsocc
TYPE
,paymentsum
TYPE
Udskrevet: 05-09-2013

s_mandt
s_carr_id
s_conn_id
s_date
s_price
s_currcode
s_planetye
s_seatsmax
s_seatsocc
s_sum
Side 4 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

,seatsmax_b
,seatsocc_b
,seatsmax_f
,seatsocc_f
,END OF ty_sflight.
DATA:
JSON_data
,ABAP_data

TYPE
TYPE
TYPE
TYPE

s_smax_b
s_socc_b
s_smax_f
s_socc_f

TYPE string
TYPE ty_sflight.

* select some data from sflight into a data structure.


SELECT SINGLE * FROM sflight INTO ABAP_data
WHERE carrid = 'AA'
AND connid = '17'
AND fldate = '20110427' .
* errorhandling is eliminated for simplification.
if sy-subrc ne 0. stop. endif.
* having the ABAP data we like to serialize these data to JSON
zcl_JSON_serializer=>serialize(
EXPORTING
IV_OBJECT_NAME = 'MyData'
ia_ABAP_data
= ABAP_data
IMPORTING
ev_JSON_data = JSON_data ).
WRITE: / JSON_data.
* clear the ABAP data
CLEAR ABAP_data.
* having the JSON data we like to deserialize these data to ABAP
zcl_JSON_serializer=>deserialize(
EXPORTING
IV_OBJECT_NAME = 'MyData'
iv_JSON_data = JSON_data
IMPORTING
ea_ABAP_data = ABAP_data
exceptions
format_error = 1 ).
if sy-subrc ne 0.
write: / 'Format error in the JSON data'.
endif.
WRITE: / ABAP_data-mandt
,ABAP_data-carrid
,ABAP_data-connid
,ABAP_data-fldate
,ABAP_data-price
,ABAP_data-currency
,ABAP_data-planetype
,ABAP_data-seatsmax
,ABAP_data-seatsocc
,ABAP_data-paymentsum
,ABAP_data-seatsmax_b
,ABAP_data-seatsocc_b
,ABAP_data-seatsmax_f
,ABAP_data-seatsocc_f.

<</LISTING 1>>
Udskrevet: 05-09-2013

Side 5 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Here we use local defined data structure as the object, we read some data from the
database into the internal ABAP data structure and calls the serialized( ) method.
This method returns the JSON data. The next step is to clear the ABAP data and to
deserialize from JSON to ABAP data.
For the JSON we want to name our data structure as "MyData", this is an optional
parameter. If we did not added this optional parameter, the data structure was
nameless.

Figur 3 ABAP data

The ABAP data is converted into the JSON format and checked in JSONLint
Validator.
<<LISTING 2 >>
Listing 2: JSON after serialize and without optional iv_object_name
{
"mandt": "000",
"carrid": "AA",
"connid": "0017",
"fldate": "20110427",
"price": "422.94 ",
"currency": "USD",
"planetype": "747-400",
"seatsmax": "385 ",
"seatsocc": "365 ",
"paymentsum": "188462.26 ",
"seatsmax_b": "31 ",
"seatsocc_b": "30 ",
"seatsmax_f": "21 ",
"seatsocc_f": "18 "
}

<</LISTING 2>>

As we are working with a data structure, the serialize is able to determine the correct
Udskrevet: 05-09-2013

Side 6 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

field name, both from local and global defined structures. For a scalar field we can't
determine the fieldname, therefore the serialize support the client for naming scarlar
fields. But you can give the aray or the object a name in JSON.
<<LISTING 3 >>
Listing 3: JSON after serialize and with optional iv_object_name
{
"MyData": {
"mandt": "000",
"carrid": "AA",
"connid": "0017",
"fldate": "20110427",
"price": "422.94 ",
"currency": "USD",
"planetype": "747-400",
"seatsmax": "385 ",
"seatsocc": "365 ",
"paymentsum": "188462.26 ",
"seatsmax_b": "31 ",
"seatsocc_b": "30 ",
"seatsmax_f": "21 ",
"seatsocc_f": "18 "
}
}

<</LISTING 3>>

For the serialize( ) method, the client can specify a object name for the scalar field,
structure or table at the topmost level. For deserialize the client can specify an object
name for the scalar field, structure or table at the topmost level. If the JSON does
have a named structure and the ABAP data point to a data structure without the
component with this name, then the client must add the parameter iv_object_name.
For deserialize the client must use a data structure in SAP similar to the JSON data
structure, but as described above the method does support IV_OBJECT_NAME.
The object can be a single scalar field or a structure of one to many fields.
For scalar field the IV_OBJECT_NAME parameter is mandatory for serialize, but
optional for deserialize.
<<LISTING 4 >>
Listing 4: Code example scalar field
DATA:
ABAP_data
,JSON_data
* select
SELECT
WHERE
AND
AND

TYPE s_sum
TYPE string.

som data from sflight into a scalar field.


SINGLE paymentsum FROM sflight INTO ABAP_data
carrid = 'AA'
connid = '17'
fldate = '20110427' .

* having the ABAP data we like to serialize this data to JSON


zcl_JSON_serializer=>serialize(
EXPORTING
iv_object_name = 'Expences'
ia_ABAP_data
= ABAP_data
IMPORTING
ev_JSON_data = JSON_data ).
* now look into the result.
WRITE: / JSON_data.
Udskrevet: 05-09-2013

Side 7 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

* clear the structure


CLEAR ABAP_data.
* having the JSON data we like to deserialize this data to ABAP
zcl_JSON_serializer=>deserialize(
EXPORTING
iv_object_name = 'Expences'
iv_JSON_data = JSON_data
IMPORTING
ea_ABAP_data = ABAP_data ).
WRITE: / ABAP_data.

<</LISTING 4>>
<<LISTING 5 >>
Listing 4: Scalar field as JSON
{
"Expences": "188462.26 "
}

<</LISTING 5>>
JSON
{
"field1": "First Value",
"field2": "second Value",
"field3": "third value"
}

ABAP
List of Scarlar fields that are not part of a structure, is not
supported in ABAP. But you just create a fixed local structure to
solve the need of a list of scalar fields. Do you need the list to
be dynamic you either dynamic build the data type in ABAP
depending on the JSON input or you ask the client to deliver
dynamic fields as table entries.

Fixed nameless data Structure


"MANDT": "000",
"NAME": "Graham Nicholson",
"AGE": "34"

}
{

Fixed named data Structure


"Data": {
"MANDT": "000",
"NAME": "Graham Nicholson",
"AGE": "34"}

}
{

Must result in the value 1 (one) as this value simulates true.


"noname":true

}
{

Must result in the value 0 (one) as this value simulates false.


"noname":false

}
{"anyname":"611"}

Udskrevet: 05-09-2013

Even though the fieldname is not the same as the fieldname in


ABAP, this value is accepted and filled into the field you
assigned in ABAP. This only works for scalar fields

Side 8 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Array

Figur 4 JSON Array

In JSON An array is an ordered collection of values. An array begins with [ (left bracket) and
ends with ] (right bracket). Values are separated by , (comma).
In ABAP we do not have arrays as in other languages, we do have however what we call
internal tables of different kinds sorted, hashed, index, standard and any tables. The tables
within ABAP can be table of fields of the same data element or data type or it could be tables
of complex structures. In JSON value could be string, number, object, array, true, false and
null. The object and array type has similarities with table of complex structures, whereas the
other have similarities with data elements or data type. True, False and null does not exists in
ABAP runtime, but we could build new data elements.
We could look at the simple type and argue that they are face less, we don't have their name
in JSON. In JSON an array could include various values of different data type, that is not the
case within ABAP, but a workaround where we use data type any or string could be used. The
Array in JSON could be a simple value table, as we in ABAP do not know the fieldname, we
can't know the correct data type, but if sender and receiver have an agreement, that the data
have fixed position, then we could used simple value tables.
examples:
["1922","1934","1962","1977","1998"]

[
{"Name":"Patrick","Birth":"1934","Month":"11"},
{"Name":"Carl","Birth":"1964","Month":"9"},
{"Name":"Jonas","Birth":"1988","Month":"3"},
{"Name":"Mogens","Birth":"1955","Month":"10"}
]
["611"]
[ { "F": 23 } ]

In ABAP this array is implmented as a standard table or


tabletype of given datatype.
I ABAP implementeres dette array med vrdier som et
tabletype or data element.You need to make an
agreement with your partner of for the datatype.
In ABAP this array is implmented as a standard table of
a given data stucture that has name, birth and month as
fields.

In JSON this is an array with ony one row, in ABAP it's


defined as a standard table of given data type and not as
a structure.
In JSON this is also an array, but now the field has a
name. In ABAP this is defined as a table of a given data
structure which only contains one field.

Lets look at an example of ordinary internal table of a structure:


Udskrevet: 05-09-2013

Side 9 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Figur 5 DDIC structure zmod_condition

<<LISTING 6 >>
Listing 6: Code example for table of simple data structure
DATA:
li_conditions
,lst_condition
,JSON_data
.

TYPE TABLE OF zmod_condition


TYPE zmod_condition
TYPE string

* get some data


SELECT * INTO TABLE li_conditions FROM zmod_condition.
"create some JSON
CLEAR JSON_data.
zcl_JSON_serializer=>serialize(
EXPORTING
ia_ABAP_data = li_conditions
IMPORTING
ev_JSON_data = JSON_data ).
WRITE:/ 'Serialize:' ,50 JSON_data.
REFRESH li_conditions.
"create some ABAP data
zcl_JSON_serializer=>deserialize(
EXPORTING
iv_JSON_data = JSON_data
IMPORTING
ea_ABAP_data = li_conditions ).
WRITE:/ 'Deserialize:' .
LOOP AT li_conditions INTO lst_condition.
WRITE:/50 sy-tabix,
lst_condition-mandt, space,
lst_condition-procid, space,
lst_condition-condid, space,
lst_condition-bis, space,
lst_condition-cond_class, space,
lst_condition-cond_method, space,
lst_condition-dummy_condition, space.
ENDLOOP.
ULINE.

<</LISTING 6>>
Udskrevet: 05-09-2013

Side 10 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

<<LISTING 7 >>
Listing 7: JSON Result
[
{
"mandt": "000",
"procid": "M01",
"condid": "C017",
"bis": "20100620",
"cond_class": "ZCL_MOD_PE_PROCESS_EXE",
"cond_method": "DUMMY_CONDITION",
"dummy_condition": ""
},
....
{
"mandt": "000",
"procid": "P93",
"condid": "C028",
"bis": "99991231",
"cond_class": "ZCL_MOD_PE_P93",
"cond_method": "DUMMY_CONDITION",
"dummy_condition": ""
}
]

<</LISTING 7>>
The JSON list continues over several entries, here you only see the first and last.

Figur 6 ABAP result as ITAB

And the let's look at a internal table of scalar fields:


<<LISTING 8 >>
Listing 8: Code example for table of single data type (array)
"zprocid is of data type CHAR 10
DATA:
li_array
,lv_element
,JSON_data
.

TYPE TABLE OF zprocid


TYPE zprocid
TYPE string

SELECT procid INTO TABLE li_array FROM zmod_process.


Udskrevet: 05-09-2013

Side 11 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

"create some JSON


CLEAR JSON_data.
zcl_JSON_serializer=>serialize(
EXPORTING
ia_ABAP_data = li_array
IMPORTING
ev_JSON_data = JSON_data ).
WRITE:/ 'Serialize:' ,50 JSON_data.
REFRESH li_array.
"create some ABAP data
zcl_JSON_serializer=>deserialize(
EXPORTING
iv_JSON_data = JSON_data
IMPORTING
ea_ABAP_data = li_array ).
WRITE:/ 'Deserialize:' .
LOOP AT li_array INTO lv_element.
WRITE:/50 sy-tabix, lv_element.
ENDLOOP.
ULINE.

<</LISTING 8>>
<<LISTING 9 >>
Listing 9: Result of Array example
[
"BPEL",
"D01",
"D02",
"L01",
...
"X01",
"X01"
]

<</LISTING 9>>

Udskrevet: 05-09-2013

Side 12 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Figur 7 ABAP debug table

Value

Figur 8 JSON Value

A value can be a string in double quotes, a number, true, false, null, an object or an
Udskrevet: 05-09-2013

Side 13 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

array. The object and array can be nested.


A value corresponds to the row element of a table type of data element within ABAP. The
ABAP parser must be able to support all nearly types of values, even though that ABAP does
not directly support true, false and null.
In ABAP you can't have a table with elements of type any, you need to know the exact data
type of a table, your ABAP table supports all build-in data types and structures equivalent to
JSONs object. But in ABAP we can't have tables of mixed data types, unless you know the
sequence of the mixed data types and that the sequence is fixed. If you make an agreement
with your partner, that you support mixed data types in specific fixed sequence, then we
could build the table as type data reference. But that will mean that you have a fixed number
of rows which does not make sense. Instead the JSON parser for ABAP support that you
interpret the mixed data types as strings.
However the JSON parser for ABAP will not support values with mixed data types including
JSON objects or JSON arrays, se example.
Remember that values are used in arrays and not in objects.
Examples:
[
"Anders Mattesen"
]

[
365
]

[
true
]

[
false
]

[
null
]

[
null,
"first string,
Udskrevet: 05-09-2013

Simple string value, in ABAP we have type data type


char with a fixed length and string with variable
length. You are better of using the string type as many
http services uses this type. Dates are often
representen as string values on the internet. I fyou
have a date, you must make an agreement on the
formatting.
Simple number, in ABAP we works with different
types of build-in numbers like byte, numeric, decimal,
integers and packed. It's most important that both
client and server make agreement on the type, length,
decimal points and format.
The value true known as boolean value is not known
in ABAP, but you could represent it as integer value 1,
or you can use SAP's funny boolean value 'X'. In this
JSON parser I use the value 1 for true. true must be in
lowercase
The value false known as boolean value is not known
in ABAP, but you could represent it as integer value 0,
or you can use SAP's funny boolean value ' '. In this
JSON parser I use the value 0 for false. false must be
in lowercase
The value null known as neither blank, zero or initial
value but simple no value, is not known in ABAP. In
the ABAP parser I interprete null as the clear version
of the field and therefore the field is cleared using
clear command. null must be in lowercase
Here we have array of mixed values. If we know the
sequence and the data type of each row, we can
support this array in ABAP. But this means that the
Side 14 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

1234,
true,
false,
"second string"

array always must have a fixed number of rows. In


ABAP you are better of by interpreting array of mixed
data types as table of strings. This is the reason that
the JSON parser for ABAP supports array of strings
and not table of data references.
Even though this is a valid JSON combination we
can't support this in ABAP as the table contains mixed
data types as values and so include the JSON object
here as a datastructure. We would have the same issue
with values including arrays.

]
[
null,
"first string",
1234,
true,
{
"Name": "JakeSmith",
"Age": "55",
"Sex": "Male"
},
false,
"secondstring"
]

<<LISTING 10 >>
Listing 10: Code example for mixed data types as values
DATA:
JSON_data
,ABAP_data
,ABAP_table

TYPE string
TYPE string
TYPE STANDARD TABLE OF string.

JSON_data = '[ null,"first string",1234, true, false,"second string"]'.


WRITE: / JSON_data.
* clear the ABAP data
CLEAR ABAP_data.
REFRESH ABAP_table.
* having the JSON data we like to deserialize these data to ABAP
zcl_JSON_serializer=>deserialize(
EXPORTING
*
iv_object_name = ''
iv_JSON_data = JSON_data
IMPORTING
ea_ABAP_data = ABAP_table
EXCEPTIONS
format_error = 1 ).
IF sy-subrc NE 0.
WRITE: / 'Format error in the JSON data'.
ENDIF.
LOOP AT ABAP_table INTO ABAP_data.
WRITE:/
ABAP_data.
ENDLOOP.

<</LISTING 10>>
<<LISTING 11 >>
Listing 11: Code example for mixed data types as integer
DATA:
JSON_data
,ABAP_data
,ABAP_table

TYPE string
TYPE i
TYPE STANDARD TABLE OF i.

FIELD-SYMBOLS:
Udskrevet: 05-09-2013

Side 15 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

<ABAP>
* initialize
APPEND 233
APPEND 234
APPEND 235

TYPE ANY.
TO ABAP_table.
TO ABAP_table.
TO ABAP_table.

* having the ABAP data we like to serialize these data to JSON


zcl_JSON_serializer=>serialize(
EXPORTING
*
iv_object_name = ''
ia_ABAP_data
= ABAP_table
IMPORTING
ev_JSON_data = JSON_data ).
WRITE: / JSON_data.
* clear the ABAP data
CLEAR ABAP_data.
REFRESH ABAP_table.
* having the JSON data we like to deserialize these data to ABAP
zcl_JSON_serializer=>deserialize(
EXPORTING
*
iv_object_name = ''
iv_JSON_data = JSON_data
IMPORTING
ea_ABAP_data = ABAP_table
EXCEPTIONS
format_error = 1 ).
IF sy-subrc NE 0.
WRITE: / 'Format error in the JSON data'.
ENDIF.
LOOP AT ABAP_table INTO ABAP_data.
WRITE:/
ABAP_data.
ENDLOOP.

<</LISTING 11>>

Udskrevet: 05-09-2013

Side 16 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

String

Figur 9 JSON String

A string is a sequence of zero or more Unicode characters, wrapped in double quotes, using
backslash escapes. A character is represented as a single character string. A string is very
much like a C or Java string.
The representation of strings is similar to conventions used in the C family of programming
languages. A string begins and ends with quotation marks. All Unicode characters may be
placed within the quotation marks except for the characters that must be escaped: quotation
mark, reverse solidus, and the control characters (U+0000 through U+001F).
Any character may be escaped. It is a requirement of the JSON spec that all data use a
Unicode encoding. In the ABAP Parser the unicode check is set active.
in ABAP you do not deal with these special control characters, that is something that is take
care of by your own framework og standard communication tool. The ABAP parser will
however strip any of these control characters.
Only the sequence of numbers, letters and special characters wrapped in double quotes, will
be passed to ABAP, and as we do not have these control characters in ABAP, no such control
value is parsed from ABAP to JSON.
Udskrevet: 05-09-2013

Side 17 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Examples:
{ "simple_string": "Anders Mattesen" }
{"date": "20131215"}

{"control": "\""}

Simple string value wrapped into quotes.


The ABAP JSON parser will interpret this date as a
string value, so any agreement af the format must be
solved after returning data from/to the parser.
Ignored likewise the values \", \\, \/, \b, \f, \n, \r, \t, or
\u four-hex-digits will be ignored. JSON Lint
Validator does not accept control either.

Number

Figur 10 JSON Number

A number is very much like a C or Java number, except that the octal and hexadecimal
formats are not used.
Whitespace can be inserted between any pair of tokens. Excepting a few encoding details,
that completely describes the language.
ABAP can convert '1.0055000075E8 ' to numeric if the data type is float, og deserialize does
support float.

{"num":"0002277891"}
{"packed":"11223377 "}
{"noname": 23.45 }
{"noname": -76.42 }
{"noname": 1.0055000075E+8 }

0002277891, here we use data type N in ABAP.


11223377, here we use data type P in ABAP.
23.45, here we use data type Decimals in ABAP
76.42-, here we use data type Decimals in ABAP
1.0055000075000000E+08, here we use data type
FLOAT

For Code examples see scalar fields in the test program.


Udskrevet: 05-09-2013

Side 18 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

ABAP Test program


It's good practice to build a test program whenever you need to build compilers/intepreters as
you need lots of testcases and many more than I can show in this article.

Figur 11 ABAP Test program

ABAP solution implemented as a class


After looking at the issues in regards to implement JSON notation as parser in ABAP,
we look deeply into the implemented ABAP code.
The objective for developing a JSON parser as a class was to build a fast and simple to use
class, that any ABAP developer can use, without knowing how it works.
The class supports the JSON format, as describe at http://www.JSON.org with only very few
limitations.
The class is named ZCL_JSON_SERIALIZER and is a concrete class.
The JSON created by the class has been tested using http://JSONlint.com.
Concept
Using a class for the encapsulation gives a number of advantages, like hiding the complexity,
reuse ability, using the class as placeholder for data. Ability to optimize or maintain code
centrally without disturbing clients as long as the methods interface does not change.
I wanted the class to support singleton design patterns, to ensure that we only have one single
instance of the object. On the other hand it was essential that the class was easy to use for
clients without knowledge about object oriented ABAP.
Udskrevet: 05-09-2013

Side 19 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

The class has three static and public methods that facilitates the singleton pattern:
SERIALIZE( ),
DESERIALIZE( ),
GET_INSTANCES( ).

When the client needs an instance of this class one of these three methods must be called. All
three using the input parameter ABAP data and JSON data, where the JSON data is of type
string and the ABAP data type data, meaning variable of any internal ABAP type. The three
methods then should dynamic investigate the actual type of data, which can be structured or
deep structured data, tables or table types, even arrays and simple plain fields. The
prerequisite is that we always have only one parameter that should be processed, however
that is not the fact in real life as we often have to deal with multiple parameters, but that is
easy to solve later by building dynamic structures at runtime. You could also use the method
COMPILE_JSON that merge multiple JSON objects into one JSON object.
One prerequisites is that the ABAP developer and WEB developer must make some kind of
agreement or contract, about what kind of data they want to exchange. ABAP does not
support de automatic declaration of data depending on contents as in java, JavaScript and
other languages. We need to know the data type.
The naming convention used in the class follows the same naming convention as in SAP
BRF+.
To be able to effective process generic and dynamic data and data structures, the ABAP
language provide these commands and build-in classes, that is used by the class and that you,
as a developer need to have some knowledge about:

GET REFERENCE OF,


FIELD-SYMBOLS,
ASSIGN,
DESCRIBE FIELD,
CL_ABAP_TYPEDESCR,
CL_ABAP_DATADESCR,
CL_ABAP_COMPLEXDESCR,
CL_ABAP_STRUCTDESCR,
CL_ABAP_TABLEDESCR,
CL_ABAP_ELEMDESCR,
CL_ABAP_REFDESCR,
CL_ABAP_OBJECTDESCR,
CL_ABAP_CLASSDESCR,
CL_ABAP_INTFDESCR.

Udskrevet: 05-09-2013

Side 20 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

As ABAP developer you should read the documentation and look into these commands and
classes. They are essential to generic- and dynamic programming.
Properties

Figur 12 Properties

It's important to set instantiation to private, this way you can control the instantiation through
factory methods, which by the way controls that the class follows the singleton design
pattern, meaning that only one instance of this class exists. It's up to you, to decide if the
class should be final or not. In your own productive version, you should assign a message
class and program status and introduce some error handling features.
As this class supports singleton design patterns, the instantiation is private. The
client has to call one of the three factory methods:
SERIALIZE( ),
DESERIALZE(),
GET_INSTANCE().
Attributes
Before looking at the methods, I would like to discuss the attributes. As principle only
Udskrevet: 05-09-2013

Side 21 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

use private attributes to ensure that only the class own methods can change
attributes. Avoid to have unnecessary attributes.

Figur 13 Attributes

The attribute GO_OBJECT is the most interesting attribute, as it contain the instance of the
class, which is used by the factory method, to check if the class has already been instantiated.
The GT_FRAGMENTS is a internal table of fragments of the JSON code, the
GR_ABAP_REF is the data reference to any ABAP data type and the GR_JSON_REF is a
data reference to the JSON string. The rest of the attributes is just some constants.
Methods

Figur 14 Methods

The class contains the a number of methods and in the following the methods is described in
details.
+CLASS_CONSTRUCTOR( ): Static/public.
Public Static method that creates variables with constant values like <space> value <space>
used later for JSON formatting. Could have been done by using constants, but easier to make
Udskrevet: 05-09-2013

Side 22 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

enhancements. The class constructor is initiated at the first the client references the class .
This is similar to initialization. As this method is the class constructor no parameters are
possible.
<<LISTING 12>>
Listing 12: CLASS CONSTRUCTOR( )
*--------------------------------------------------------------------*
* Create variables with constant values like <space> value <space>
*
* used later for JSON format.
*
*--------------------------------------------------------------------*
method class_constructor.
cl_ABAP_string_utilities=>c2str_preserving_blanks(
exporting source = ':'
importing dest
= c_colon ) .
cl_ABAP_string_utilities=>c2str_preserving_blanks(
exporting source = ','
importing dest
= c_comma ) .
cl_ABAP_string_utilities=>c2str_preserving_blanks(
exporting source = '"'
importing dest
= c_quotes ) .
endmethod.

<</LISTING 12>>

This method reuses SAP standard classes.


+CONSTRUCTOR(DATA) : Instance/public.

Figur 15 Constructor signature

Public method with the only purpose to create the data references to ABAP and JSON data
and save these as instance attributes like, "me->gr_ABAP_ref " og "me->gr_JSON_ref " . Later
when other methods process the data, we can easily analyze data references an deduce
original data types.
Even though this method is declared as instance/public, you cant call it directly as the class is
defined with private instantiation, meaning that you have to call some kind of factory
method, to get an instance. The class happens to have 3 such methods get_instanse( ),
serialize( ) and deserialize( ). At the same time the class supports the singleton design
patterns, and therefore the client can be sure that the class is instantiated only once.
Later when analyzing the data we need to parse, we always uses the GR_ABAP_DATA
reference to dynamic interpret the data type like scalar fields, internal table or complex data
structure. The GR_JSON_DATA is used as source or target for the JSON data.
Udskrevet: 05-09-2013

Side 23 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

<<LISTING 13>>
Listing 13: CONSTRUCTOR( )
*--------------------------------------------------------------------*
* set data references for ABAP and JSON data, both parameters will
*
* always be of some type of data and as we have to support initial
*
* values no checks for value is done here.
*
*--------------------------------------------------------------------*
method constructor.
get reference of ia_ABAP_data into me->gr_ABAP_ref .
get reference of iv_JSON_data into me->gr_JSON_ref .
endmethod.

<</LISTING 13>>

By using data references and field symbols, we are able to work with generic/dynamic data.
+GET_INSTANCE( ): Static/Public.

Figur 16 Get Instance signature

Public Static Factory method with the purpose to return one instance of the class. The class
supports singleton design patterns and therefore this method check if we already have an
instance, otherwise a new instance is created by command CREATE OBJECT and thereby
the calling the constructor method. Bear in mind that the methods serialize( ) and deserialize(
) also are defined as factory methods and thereby able to instantiate the class. In practical the
get_instance( ) is seldom used. The factory method ensures, that the client do not need to
know if we already have an instance or not, the client just make the call, then it's up to the
class method to take responsibility for only having one instance.
<<LISTING 14>>
Listing 14: GET_INSTANCE ( )
*--------------------------------------------------------------------*
* Get singleton instance, return existing instance or create new one *
* Always reset the ABAP and JSON data references, as the client can *
* make multiple calls using different type of data
*
*--------------------------------------------------------------------*
METHOD get_instance.
IF go_object IS BOUND.
ro_instance = go_object.
go_object->set_ABAP_data( ia_ABAP_data = ia_ABAP_data ).
go_object->set_JSON_data( iv_JSON_data = iv_JSON_data ).
ELSE.
CREATE OBJECT go_object
EXPORTING
ia_ABAP_data = ia_ABAP_data
iv_JSON_data = iv_JSON_data.
Udskrevet: 05-09-2013

Side 24 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

ro_instance = go_object.
ENDIF.

ENDMETHOD. <</LISTING 14>>

+GET_ABAP_DATA( ): instance/public.

Figur 17 Get_ABAP_Data signature

Public Instance method, that returns deserialized data as ABAP data type. Every time the
class process ABAP data, this data is stored in the class and thereby easy to return. In
practical this method is seldom used() by the client as the serialize( ) and deserialize( )
methods exports the needed data.
<<LISTING 15>>
Listing 15: GET_ABAP_DATA ( )
*--------------------------------------------------------------------*
* Utility for returning the ABAP data if needed
*
*--------------------------------------------------------------------*
method get_ABAP_data.
field-symbols
<data>
type data .
assign me->gr_ABAP_ref->* to <data> .
ea_data = <data>.
endmethod.

<</LISTING 15>>

+SET_ABAP_DATA( ): instance/public.

Figur 18 SET_ABAP_DATA signature

Public Instance method used for setting the ABAP data type and then clearing previous
fragments. In practical this method is seldom used by the client as the serialize( ) and
deserialize( ) methods uses the method.
<<LISTING 16 >>
Listing 16: SET_ABAP_DATA ( )
*--------------------------------------------------------------------*
* Set instance variable ABAP_ref and clear any former fragments
*
*--------------------------------------------------------------------*
method set_ABAP_data.
get reference of ia_ABAP_data into zcl_JSON_serializer=>gr_ABAP_ref .
clear zcl_JSON_serializer=>gt_fragments.
endmethod.
Udskrevet: 05-09-2013

Side 25 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

<</LISTING 16>>

+GET_JSON_DATA( ): instance/public.

Figur 19 GET_JSON_DATA signatures

Public Instance method with the purpose to return the serialized JSON string. To be
successful to serialize ABAP data, the data type must be known and must contain data. In
practical this method is seldom used by the client as the serialize( ) and deserialize( ) methods
uses the method.
<<LISTING 17 >>
Listing 17: GET_JSON_DATA ( )
*--------------------------------------------------------------------*
* return the serialized string from fragments to JSON data
*
*--------------------------------------------------------------------*
method get_JSON_data.
concatenate lines of me->gt_fragments into ev_data .
endmethod.

<</LISTING 17>>

+SET_JSON_DATA( ) : instance/public

Figur 20 SET_JSON_DATA Signatures

Public Instance method with the purpose to receive a serialized JSON string containing JSON
formatted data and deserialize to ABAP data of an known data type. In practical this method
is seldom used by the client as the serialize( ) and deserialize( ) methods uses the method.
<<LISTING 18 >>
Listing 18: SET_JSON_DATA ( )
*--------------------------------------------------------------------*
* set class attribute with JSON data and clear former fragments
*
*--------------------------------------------------------------------*
method set_JSON_data.
get reference of iv_JSON_data into zcl_JSON_serializer=>gr_JSON_ref .
clear zcl_JSON_serializer=>gt_fragments.
endmethod.

<</LISTING 18>>

Udskrevet: 05-09-2013

Side 26 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

+SERIALIZE( ): static/public

Figur 21 SERIALIZE Signatures

Public Static method with the purpose to serialize any ABAP data source into an JSON string.
This method is one of two often used methods by the client. The method is also a factory
method, creating new instance if one does not already exists.
This method is simple as it only deals with very few task, but it's from here we trigger the
more complex serialization by calling an recursive serializer.
<<LISTING 19>>
Listing 19: SERIALIZE( )
*--------------------------------------------------------------------*
* Static factory method. This method support singletons and therefore*
* the method check if the object is instantiated. If not call the
*
* constructor, else reset the former data and assign the ABAP and
*
* and JSON data.
*
*--------------------------------------------------------------------*
METHOD serialize.
FIELD-SYMBOLS
<data>
TYPE data
.
* Get the instance of the class
go_object = get_instance( ia_ABAP_data = ia_ABAP_data
iv_JSON_data = ev_JSON_data ).
* Assign instance ABAP data reference to field symbols
ASSIGN go_object->gr_ABAP_ref->* TO <data> .
* Do the serialization recursively
go_object->serialize_recursive( EXPORTING
iv_object_name = iv_object_name
ia_data
= <data> ) .
* Get the JSON data
go_object->get_JSON_data( IMPORTING ev_data = ev_JSON_data ).
* Return the Instance
eo_instance = go_object.
ENDMETHOD.

<</LISTING 19>>

Serialize supports singleton patterns by calling the get_instance( ) method.


After assigning the ABAP data reference this method calls the recursive and private method
serialize_recursive( ) which produce the JSON data using ABAP data as input.
Finally the method exports both the JSON data and the instance to the client.
Udskrevet: 05-09-2013

Side 27 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

-SERIALIZE_RECURSIVE( ): instance/private

Figur 22 SERIALIZE_RECURSIVE Signatures

Private instance method, with the purpose to serialize the ABAP data type into JSON format.
This method uses recursion for serializing and decompiling deep structures of ABAP data.
The client are not aware about this method. This method is used often and must be optimized.
As the method is private it's secure to change the implementation without disturbing clients.
But it's also in this method we analyse the dynamic ABAP data type by using SAP AG
provided classes and complex ABAP commands. We need to analyse each component of the
dynamic ABAP data type. This method is the hart of the JSON parser, so be careful if you
change this method.
As the JSON data is just a structured string field we can only use the ABAP data for
analyzing.
<<LISTING 20>>
Listing 20: SERIALIZE_RECURSIVE( )
*--------------------------------------------------------------------*
* Method which takes any ABAP data and pass it as a JSON string.
*
* input is any ABAP datatype, and only few of the ABAP datatypes are *
* not supported as more sophisticated datatypes. Basically the data *
* is either a structred datatype like tables and structures or it is *
* a scalar datatype. This method supports data structures and deep
*
* data structures as it supports all typical scalar data types, for *
* seing which scalar types we do not support look in this code.
*
*--------------------------------------------------------------------*
method serialize_recursive.
data:
lv_type
type c ,
lv_comps
type i ,
lv_lines
type i ,
lv_index
type i ,
lv_value
type string .
field-symbols:
<itab>
<comp>

type any table ,


type any .

describe field ia_data type lv_type components lv_comps .


"------------------------------------------------------------------*
" Table
"------------------------------------------------------------------*
if lv_type = cl_ABAP_typedescr=>typekind_table .
*
itab -> array
append '[' to me->gt_fragments .
assign ia_data to <itab> .
lv_lines = lines( <itab> ) .
loop at <itab> assigning <comp> .
add 1 to lv_index .
Udskrevet: 05-09-2013

Side 28 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

serialize_recursive(
exporting
ia_data
= <comp>
iv_recursive_call = 'X') .
if lv_index < lv_lines .
append c_comma to me->gt_fragments .
endif .
endloop .
append ']' to gt_fragments .
else .
"------------------------------------------------------------------*
" If components are initial and method called from serialize we
*
" are working with a single standalone scarlarfield without name
*
" we only know the data type, not the field name. Therefore the
*
" datatype is used as the fieldname since an JSON object must have *
" an object name and must be surrounded by brackets
*
"{"name":"value"}. Scalar fields are allways single field values, *
" nor part of a structure or tabletype.
*
"If components are initial and method is called recursive from
*
"serial_recursive, the scarlar field is part of an object or array *
" and there by have a name.
"------------------------------------------------------------------*
if lv_comps is initial .
*
field -> scalar
*
todo: format
lv_value = ia_data .
replace all occurrences of '\'
in lv_value with '\\' .
replace all occurrences of ''''
in lv_value with '\''' .
replace all occurrences of '"'
in lv_value with '\"' .
replace all occurrences of '&'
in lv_value with '\&' .
replace all occurrences of cl_ABAP_char_utilities=>cr_lf
in lv_value with '\r\n' .
replace all occurrences of cl_ABAP_char_utilities=>newline
in lv_value with '\n' .
replace all occurrences of cl_ABAP_char_utilities=>horizontal_tab
in lv_value with '\t' .
replace all occurrences of cl_ABAP_char_utilities=>backspace
in lv_value with '\b' .
replace all occurrences of cl_ABAP_char_utilities=>form_feed
in lv_value with '\f' .
if iv_recursive_call is initial.
if iv_object_name is not initial.
concatenate '{"' iv_object_name '":' '"' lv_value '"' '}'
into lv_value .
else.
case lv_type.
when cl_ABAP_typedescr=>typekind_num.
concatenate '{"num":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_date.
concatenate '{"date":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_packed.
concatenate '{"packed":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_time.
concatenate '{"time":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_char.
concatenate '{"char":' '"' lv_value '"' '}' into lv_value .
Udskrevet: 05-09-2013

Side 29 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

when cl_ABAP_typedescr=>typekind_hex.
concatenate '{"hex":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_float.
concatenate '{"float":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_int.
concatenate '{"int":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_int1.
concatenate '{"int1":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_int2.
concatenate '{"int2":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_w.
concatenate '{"Wide":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_oref.
concatenate '{"Object reference, not supported":'(j01) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_string.
concatenate '{"string":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_xstring.
concatenate '{"xtring":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_dref.
concatenate '{"Data reference, not supported":'(j02) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_class.
concatenate '{"Class reference, not supported":'(j03) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_intf.
concatenate '{"Class reference, not supported":'(j04) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_any.
concatenate '{"Type Any, not supported":'(j05) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_data.
concatenate '{"Type data, not supported":'(j06) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_simple.
concatenate '{"Type clike, not supported":'(j07) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_csequence.
concatenate '{"Type csequence, not supported":'(j08) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_xsequence.
concatenate '{"Type xsequence, not supported":'(j09) '"'
lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_numeric.
concatenate '{"numeric":' '"' lv_value '"' '}' into lv_value .
when cl_ABAP_typedescr=>typekind_iref.
concatenate '{"Instance reference, not supported":'(j10) '"'
lv_value '"' '}' into lv_value .
when others.
concatenate '{"NOT SUPPORTED":'(j11) '"' lv_value '"' '}'
into lv_value .
endcase.
endif.
else.
concatenate '"' lv_value '"' into lv_value .
endif.
condense lv_value.
append lv_value to me->gt_fragments .
else .
"------------------------------------------------------------------*
" Structure
Udskrevet: 05-09-2013

Side 30 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

"------------------------------------------------------------------*
data lv_typedescr type ref to cl_ABAP_structdescr .
field-symbols <ABAPcomp> type ABAP_compdescr .
append '{' to me->gt_fragments .
lv_typedescr ?= cl_ABAP_typedescr=>describe_by_data( ia_data ) .
loop at lv_typedescr->components assigning <ABAPcomp> .
lv_index = sy-tabix .
concatenate '"' <ABAPcomp>-name '"' c_colon into lv_value .
translate lv_value to lower case .
append lv_value to me->gt_fragments .
assign component <ABAPcomp>-name of structure ia_data to <comp> .
serialize_recursive(
exporting
ia_data
= <comp>
iv_recursive_call = 'X' ).
if lv_index < lv_comps .
append c_comma to me->gt_fragments .
endif .
endloop .
append '}' to me->gt_fragments .
endif .
endif .
endmethod.

<</LISTING 20>>

This method analyses the ABAP data type/structure by using some of the more complex
ABAP commands and build-in classes, it's worth the effort to fully understand what's
happening. use this solution as inspiration when working with dynamic/generic data.
+DESERIALIZE( ): static/public

Figur 23 DESERIALIZE Signature

Public static method, in order to deserialize JSON string into any ABAP data source.
This method are one of two often used methods for the ABAP developer. The method is also
a factory method, creating new instance if one does not already exists. Serialize is the most
common used method.
This method is simple as it only deals with very few task, but it's from here we trigger the
more complex deserialization by calling an recursive deserializer.
<<LISTING 21 >>
Listing 21: DESERIALIZE ( )
*--------------------------------------------------------------------*
* Static factory method. This method support singletons and therefore*
Udskrevet: 05-09-2013

Side 31 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

* the method check if the object is instantiated. If not call the


*
* constructor, else reset the former data and assign the ABAP and
*
* and JSON data.
*
*--------------------------------------------------------------------*
METHOD deserialize.
DATA:
lv_name
TYPE string
,lv_fragment
TYPE string
,lv_index
TYPE i.
FIELD-SYMBOLS:
<data>

TYPE data .

* makes no sense to continue without JSON data


CHECK iv_JSON_data IS NOT INITIAL.
* Get the instance of the class
go_object = get_instance( ia_ABAP_data = ea_ABAP_data
iv_JSON_data = iv_JSON_data ).
* Assign the attribute of reference to ABAP data to a field symbol
ASSIGN zcl_JSON_serializer=>gr_ABAP_ref->* TO <data> .
* fragments the JSON data into internal table
go_object->fragments_JSON_data( EXPORTING
iv_JSON_data = iv_JSON_data
EXCEPTIONS
format_error = 1 ).
IF sy-subrc NE 0.
RAISE format_error.
ENDIF.
* if object name is filled we must remove the object name from fragments as
* it's not part of the ABAP data but plays the role as name of the ABAP data.
IF iv_object_name IS NOT INITIAL.
READ TABLE go_object->gt_fragments INDEX 1 INTO lv_fragment.
IF lv_fragment NE '{'.
RAISE format_error.
ENDIF.
CONCATENATE '"' iv_object_name '":' INTO lv_name.
READ TABLE go_object->gt_fragments INDEX 2 INTO lv_fragment.
IF lv_name NE lv_fragment.
RAISE format_error.
ENDIF.
DESCRIBE TABLE go_object->gt_fragments LINES lv_index.
READ TABLE go_object->gt_fragments INDEX lv_index INTO lv_fragment.
IF lv_fragment NE '}'.
RAISE format_error.
ENDIF.
DELETE go_object->gt_fragments INDEX lv_index.
DELETE go_object->gt_fragments INDEX 1.
DELETE go_object->gt_fragments INDEX 1.
ENDIF.
* deserialize in depth using recursion
go_object->deserialize_recursive( CHANGING
ca_data = ea_ABAP_data
EXCEPTIONS
format_error = 1 ) .
Udskrevet: 05-09-2013

Side 32 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

IF sy-subrc NE 0.
RAISE format_error.
ENDIF.
* set the ABAP data in instance
go_object->set_ABAP_data( EXPORTING

ia_ABAP_data = ea_ABAP_data ).

* export the instance


eo_instance = go_object.
ENDMETHOD.

<</LISTING 21>>

Serialize supports singleton patterns by calling the get_instance( ) method.


After assigning the ABAP data reference the method divide the JSON data into fragments and
then calls the recursive and private method deserialize_recursive( ) which produce the ABAP
data using JSOB data as input.
Finally the method exports both the ABAP data and the instance to the client.
-DESERIALIZE_RECURSIVE( ): instance/private

Figur 24 DESERIALIZE_RECURSIVE Signature

Private instance method with the purpose to deserialize JSON into ABAP data source, this
method uses recursion for decompiling deep structures. The client is not aware about this
method.
This method is used often and must be optimized. As the method is private it's safe to change
the implementation without disturbing clients.
But it's also in this method we analyse the dynamic ABAP data type by using SAP AG
provided classes and complex ABAP commands. We need to analyse each component of the
dynamic ABAP data type. This method is the hart of the JSON parser, so be careful if you
change this method.
As the JSON data is just a structured string field we can only use the ABAP data for
analyzing, therefore the starting point is the ABAP data. The method then looks up in the
fragments table to find something that we expect from the ABAP data point of view, if we do
not find what we expected you get the format error exception.
Udskrevet: 05-09-2013

Side 33 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

<<LISTING 22 >>
Listing 22: DESERIALIZE_RECURSIVE ( )
*--------------------------------------------------------------------*
* As with serialize this method serialize fragments but instead of
*
* adding fragment this method delete fragment from fragments and
*
* update the ABAP data
*
*--------------------------------------------------------------------*
method deserialize_recursive.
data:
lv_type
type c
"#EC NEEDED
,lv_comps
type i
"#EC NEEDED
,lv_lines
type i
,lv_index
type i
,lo_typedescr
type ref to cl_ABAP_structdescr
,lo_datadescr
type ref to cl_ABAP_datadescr
,lo_tabledescr
type ref to cl_ABAP_tabledescr
,lo_elemdescr
type ref to cl_ABAP_elemdescr
"#EC NEEDED
,lv_name
type string
,lv_data
type string
,lr_row
type ref to data
.
field-symbols:
<ABAPcomp>
<atab>
<itab>
<xtab>
<htab>
<stab>
<comp>

type
type
type
type
type
type
type

ABAP_compdescr,
any table,
standard table ,
index table,
hashed table,
sorted table,
any .

describe field ca_data type lv_type components lv_comps .


"Check metadata for the parameter data
lo_datadescr ?= cl_ABAP_datadescr=>describe_by_data( ca_data ) .
"------------------------------------------------------------------*
" Table: supporting all table types
"------------------------------------------------------------------*
case lo_datadescr->kind.
"Data is of type table
when cl_ABAP_datadescr=>kind_table.
lo_tabledescr ?= cl_ABAP_typedescr=>describe_by_data( ca_data ) .

case lo_tabledescr->table_kind.
when cl_ABAP_tabledescr=>tablekind_any.
"ANY TABLE includes all table types and therefore we might
"not reach this code
assign ca_data to <atab> .
read table gt_fragments index 1 into lv_data.
concatenate '"' iv_name '": ' into lv_name.
translate: lv_name to lower case
,lv_data to lower case.
condense lv_name.
single row for table without array tag?
if lv_data = '{'.
create data lr_row like line of <itab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.

Udskrevet: 05-09-2013

Side 34 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <itab>.
endloop.
array of 1:m rows with table tag
elseif lv_data = '[' or lv_data = lv_name.
if lv_data ne '['.
delete gt_fragments index 1.
endif.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
if lv_data eq ']'.
delete gt_fragments index 1.
return. "Empty table, which is not an error
endif.
create data lr_row like line of <atab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
collect <comp> into <atab>.
read table gt_fragments index 1 into lv_data.
if lv_data = ','. "new row is assumed
delete gt_fragments index 1.
continue.
elseif lv_data = ']'.
delete gt_fragments index 1.
exit.
else.
raise format_error.
endif.
endloop.
else.
raise format_error.
endif.
when cl_ABAP_tabledescr=>tablekind_std.
assign ca_data to <itab> .
read table gt_fragments index 1 into lv_data.
concatenate '"' iv_name '": ' into lv_name.
translate: lv_name to lower case
,lv_data to lower case.
condense lv_name.

single row for table without array tag?


if lv_data = '{'.

Udskrevet: 05-09-2013

Side 35 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

create data lr_row like line of <itab>.


loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <itab>.
endloop.
array with 1:m rows and with array tag
elseif lv_data = '[' or lv_data = lv_name.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
if lv_data eq ']'.
delete gt_fragments index 1.
return. "Empty table, which is not an error
endif.
create data lr_row like line of <itab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <itab>.
read table gt_fragments index 1 into lv_data.
if lv_data = ','. "new row is assumed
delete gt_fragments index 1.
continue.
elseif lv_data = ']'.
delete gt_fragments index 1.
exit.
else.
raise format_error.
endif.
endloop.
else.
raise format_error.
endif.
when cl_ABAP_tabledescr=>tablekind_index.
"INDEX TABLE includes all standard tables and sorted tables
"therefore we might not reach this code
assign ca_data to <xtab> .
read table gt_fragments index 1 into lv_data.
concatenate '"' iv_name '": ' into lv_name.
translate: lv_name to lower case
,lv_data to lower case.
condense lv_name.

Udskrevet: 05-09-2013

Side 36 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

single row for table without array tag?


if lv_data = '{'.
create data lr_row like line of <itab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <itab>.
endloop.
array of 1:m rows with array tag
elseif lv_data = '[' or lv_data = lv_name.
if lv_data ne '['.
delete gt_fragments index 1.
endif.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
if lv_data eq ']'.
delete gt_fragments index 1.
return. "Empty table, which is not an error
endif.
create data lr_row like line of <xtab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <xtab>.
read table gt_fragments index 1 into lv_data.
if lv_data = ','. "new row is assumed
delete gt_fragments index 1.
continue.
elseif lv_data = ']'.
delete gt_fragments index 1.
exit.
else.
raise format_error.
endif.
endloop.
else.
raise format_error.
endif.
when cl_ABAP_tabledescr=>tablekind_hashed.
assign ca_data to <htab> .
read table gt_fragments index 1 into lv_data.
concatenate '"' iv_name '": ' into lv_name.
translate: lv_name to lower case

Udskrevet: 05-09-2013

Side 37 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

,lv_data to lower case.


condense lv_name.
single row for table without array tag?
if lv_data = '{'.
create data lr_row like line of <itab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <itab>.
endloop.
array of 1:m rows with array tag
elseif lv_data = '[' or lv_data = lv_name.
if lv_data ne '['.
delete gt_fragments index 1.
endif.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
if lv_data eq ']'.
delete gt_fragments index 1.
return. "Empty table, which is not an error
endif.
create data lr_row like line of <htab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
collect <comp> into <htab>.
read table gt_fragments index 1 into lv_data.
if lv_data = ','. "new row is assumed
delete gt_fragments index 1.
continue.
elseif lv_data = ']'.
delete gt_fragments index 1.
exit.
else.
raise format_error.
endif.
endloop.
else.
raise format_error.
endif.
when cl_ABAP_tabledescr=>tablekind_sorted.
assign ca_data to <stab> .
read table gt_fragments index 1 into lv_data.
concatenate '"' iv_name '": ' into lv_name.

Udskrevet: 05-09-2013

Side 38 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

translate: lv_name to lower case


,lv_data to lower case.
condense lv_name.
single row for table without array tag?
if lv_data = '{'.
create data lr_row like line of <itab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <itab>.
endloop.
array of 1:m rows with array tag
elseif lv_data = '[' or lv_data = lv_name.
if lv_data ne '['.
delete gt_fragments index 1.
endif.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
if lv_data eq ']'.
delete gt_fragments index 1.
return. "Empty table, which is not an error
endif.
create data lr_row like line of <stab>.
loop at gt_fragments into lv_data.
assign lr_row->* to <comp>.
deserialize_recursive(
changing
ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
append <comp> to <stab>.
read table gt_fragments index 1 into lv_data.
if lv_data = ','. "new row is assumed
delete gt_fragments index 1.
continue.
elseif lv_data = ']'.
delete gt_fragments index 1.
exit.
else.
raise format_error.
endif.
endloop.
else.
raise format_error.
endif.
when others.
raise format_error.

Udskrevet: 05-09-2013

Side 39 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

endcase.
"----------------------------------------------------------------*
" Type Element
"----------------------------------------------------------------*
when cl_ABAP_datadescr=>kind_elem.
lo_elemdescr ?= cl_ABAP_elemdescr=>describe_by_data( ca_data ) .
"Field part of a data structure
if iv_name is not initial.
concatenate '"' iv_name '":' into lv_name.
translate lv_name to lower case.
read table gt_fragments index 1 into lv_data.
translate lv_data to upper case.
translate lv_name to upper case.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
replace all occurrences of '"' in lv_data with ''.
condense lv_data.
case lv_data.
when 'true'.
ca_data = '1'.
when 'false'.
ca_data = '0'.
when 'null'.
ca_data = ''.
when others.
ca_data = lv_data.
endcase.
delete gt_fragments index 1.
else. "Scalar field (single field)
read table gt_fragments index 1 into lv_data.
if lv_data = '{'.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
find first occurrence of ':' in lv_data.
if sy-subrc ne 0.
raise format_error.
endif.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
if lv_data(1) = '"'.
replace all occurrences of '"' in lv_data with ''.
condense lv_data.
ca_data = lv_data.
else.
replace all occurrences of '"' in lv_data with ''.
condense lv_data.
case lv_data.
when 'true'.
ca_data = '1'.
when 'false'.
ca_data = '0'.
when 'null'.
ca_data = ''.
when others.
ca_data = lv_data.
endcase.
endif.
delete gt_fragments index 1.
read table gt_fragments index 1 into lv_data.
Udskrevet: 05-09-2013

Side 40 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

if lv_data = '}'.
delete gt_fragments index 1.
exit.
else.
raise format_error.
endif.
elseif lv_data(1) = '"'.
read table gt_fragments index 1 into lv_data.
replace all occurrences of '"' in lv_data with ''.
condense lv_data.
ca_data = lv_data.
delete gt_fragments index 1.
exit.
else.
read table gt_fragments index 1 into lv_data.
if lv_data(1) = '"'.
replace all occurrences of '"' in lv_data with ''.
condense lv_data.
ca_data = lv_data.
else.
replace all occurrences of '"' in lv_data with ''.
condense lv_data.
case lv_data.
when 'true'.
ca_data = '1'.
when 'false'.
ca_data = '0'.
when 'null'.
ca_data = ''.
when others.
ca_data = lv_data.
endcase.
endif.
delete gt_fragments index 1.
exit.
endif.
endif.
when cl_ABAP_datadescr=>kind_struct.
lo_typedescr ?= cl_ABAP_structdescr=>describe_by_data( ca_data ) .
lv_lines = lines( lo_typedescr->components ) .
read table gt_fragments index 1 into lv_data.
if lv_data = '{'.
delete gt_fragments index 1.
else.
read table gt_fragments index 2 into lv_data.
if lv_data = '{'.
delete gt_fragments index 1.
delete gt_fragments index 1.
else.
raise format_error.
endif.
endif.
loop at lo_typedescr->components assigning <ABAPcomp> .
lv_index = sy-tabix.
assign component <ABAPcomp>-name of structure ca_data to <comp> .
deserialize_recursive(
exporting
iv_name = <ABAPcomp>-name
changing
Udskrevet: 05-09-2013

Side 41 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

ca_data = <comp>
exceptions
format_error = 1 ) .
if sy-subrc ne 0.
raise format_error.
endif.
if lv_index < lv_lines.
read table gt_fragments index 1 into lv_data.
if lv_data = ','.
delete gt_fragments index 1.
elseif lv_data = '}'.
exit. "structure closed before last field, this is acceptable
else.
raise format_error.
endif.
endif.
endloop .
read table gt_fragments index 1 into lv_data.
if lv_data = '}'.
delete gt_fragments index 1.
else.
raise format_error.
endif.
when cl_ABAP_datadescr=>kind_ref.
raise datatype_not_supported.
when cl_ABAP_datadescr=>kind_class.
raise datatype_not_supported.
when cl_ABAP_datadescr=>kind_intf.
raise datatype_not_supported.
when others.
raise datatype_not_supported.
endcase.
endmethod.

<</LISTING 22>>

This method analyses the ABAP data type/structure by using some of the more complex
ABAP commands and build-in classes, it's worth the effort to fully understand what's
happening. use this solution as inspiration when working with dynamic/generic data.
+COMPILE_JSON( ): static/public

Figur 25 Compile_JSON Signatures

Public static method used for combining multiple JSON Objects into a combined JSON
object. This method is more or less a helper method, as the client often works with several
JSON objects and often needs to merge JSON objects into one merged object.
Udskrevet: 05-09-2013

Side 42 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

<<LISTING 23 >>
Listing 23: COMPILE_JSON ( )
*--------------------------------------------------------------------*
* This method combines a collection of JSON Objects into one single *
* JSON object by surrounding the members with "{" and "}".
*
*--------------------------------------------------------------------*
method compile_JSONs.
constants:
co_true
type boolean_01 value 1
,co_false
type boolean_01 value 0 .
data:
lv_with_root

type boolean_01 value 0.

field-symbols:
<JSON_object>

type zJSON_object.

clear ev_JSON_data.
loop at it_JSON_objects assigning <JSON_object>.
if <JSON_object>-id is initial.
lv_with_root = co_false.
concatenate ev_JSON_data '[' <JSON_object>-tx into ev_JSON_data.
else.
lv_with_root = co_true.
concatenate ev_JSON_data ',"' <JSON_object>-id '":' <JSON_object>-tx
into ev_JSON_data.
endif.
endloop.
shift ev_JSON_data.
if lv_with_root = co_true.
concatenate '{' ev_JSON_data '}' into ev_JSON_data.
endif.
endmethod.

<</LISTING 23>>

-FRAGMENTS_JSON_DATA( ): instance/private

Figur 26 FRAGMENTS_JSON_DATA Signature

This method is a private instance helper function that facilitates the class itself with splitting
JSON data into fragments within an ordinary internal table. The method is called by the
deserialize method. This method have knowledge about the JSON notation. The method takes
the JSON data as input and split it up into the fragments that are in interest.
<<LISTING 24 >>
Udskrevet: 05-09-2013

Side 43 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Listing 24: FRAGMENTS_JSON_DATA ( )


*--------------------------------------------------------------------*
* This method fragmentate the JSON string into collection/internal
*
* table of fragments providing easy proces of data
*
*--------------------------------------------------------------------*
method fragments_JSON_data.
CONSTANTS:
true
TYPE boolean_01 VALUE 1
,false
TYPE boolean_01 VALUE 0
.
DATA:
lv_length
TYPE i VALUE 0
,lv_i
TYPE i VALUE 0
,lv_c
TYPE c
,lv_fragment
TYPE string
,lv_JSON_string
TYPE string
,lv_quotation_block_on
TYPE boolean
.
FIELD-SYMBOLS:
<data>

TYPE data .

REFRESH gt_fragments.
lv_JSON_string = iv_JSON_data.
*** do not condense JSON_string with no gaps as spaces between words do disapear
*** CONDENSE JSON_string no-gaps.
lv_length = STRLEN( lv_JSON_string ).
"validate JSON_string, the first character must be { or [
"the last be be } or ]
IF lv_JSON_string+lv_i(1) NE '[' AND
lv_JSON_string+lv_i(1) NE '{'.
RAISE format_error.
ENDIF.
SUBTRACT 1 FROM lv_length.
IF lv_JSON_string+lv_length(1) NE ']' AND
lv_JSON_string+lv_length(1) NE '}'.
RAISE format_error.
ENDIF.
ADD 1 TO lv_length.
WHILE lv_i < lv_length.
lv_c = lv_JSON_string+lv_i(1).
CASE lv_c.
when ' '.
IF lv_quotation_block_on = true.
CONCATENATE lv_fragment lv_c INTO lv_fragment RESPECTING BLANKS.
endif.
WHEN '{' OR '}' OR '[' OR ']' .
IF lv_quotation_block_on = true.
CONCATENATE lv_fragment lv_c INTO lv_fragment.
ELSE.
IF lv_fragment IS NOT INITIAL.
APPEND lv_fragment
TO gt_fragments.
ENDIF.
APPEND lv_JSON_string+lv_i(1) TO gt_fragments.
CLEAR lv_fragment.
ENDIF.
WHEN ','.
IF lv_quotation_block_on = true.
Udskrevet: 05-09-2013

Side 44 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

CONCATENATE lv_fragment lv_c INTO lv_fragment.


ELSE.
IF lv_fragment IS NOT INITIAL.
CONDENSE lv_fragment.
APPEND lv_fragment
TO gt_fragments.
ENDIF.
APPEND lv_JSON_string+lv_i(1) TO gt_fragments.
CLEAR lv_fragment.
ENDIF.
WHEN '"'.
IF lv_quotation_block_on = true.
lv_quotation_block_on = false.
ELSE.
lv_quotation_block_on = true.
ENDIF.
CONCATENATE lv_fragment lv_c INTO lv_fragment.
WHEN ':'.
"remember that ':' within quotation as value is allowed
IF lv_quotation_block_on = true.
CONCATENATE lv_fragment lv_c INTO lv_fragment RESPECTING BLANKS.
ELSE.
CONCATENATE lv_fragment lv_c INTO lv_fragment.
CONDENSE lv_fragment.
APPEND lv_fragment
TO gt_fragments.
CLEAR lv_fragment.
ENDIF.
WHEN OTHERS.
CONCATENATE lv_fragment lv_c INTO lv_fragment RESPECTING BLANKS.
ENDCASE.
ADD 1 TO lv_i.
ENDWHILE.
endmethod.

<</LISTING 24>>

The fragments method is very important and processed the JSON data byte by byte. Be
careful if you make changes in this method and always check impact of changes on the
performance. Be aware about the lv_qoutation_block_on which track if a string has been
started or finished.
Lets see what's behind the scene in the debugger when we want to deserialize the JSON
<<LISTING 25 >>
Listing 25: JSON Result
{
"MyData": {
"mandt": "000",
"carrid": "AA",
"connid": "0017",
"fldate": "20110427",
"price": "422.94 ",
"currency": "USD",
"planetype": "747-400",
"seatsmax": "385 ",
"seatsocc": "365 ",
"paymentsum": "188462.26 ",
"seatsmax_b": "31 ",
"seatsocc_b": "30 ",
"seatsmax_f": "21 ",
"seatsocc_f": "18 "
}
Udskrevet: 05-09-2013

Side 45 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

<</LISTING 25>>

Figur 27 Debug Example

Here you see that the fragments table contains the field values and JSON notation characters.
We use the JSON control characters to understand what we received and the field values for
mapping into the ABAP data structure. But keep in mind that this method mission is only
about splitting the JSON data into JSON control characters and field values. In this example
all fields are string fields.

Udskrevet: 05-09-2013

Side 46 af 47

BGS Consulting ApS


Krmindevej 3
3500 Vrlse
Danmark

Summary
Having build your own JSON parser for ABAP, you have a common tool for all your
comming projects that need to parse to/from JSON. And even if you not need a JSON
parser, you now got some ideas to build other parsers like an XML parser. Do also look
into SCN to find other similar solutions.

On the Web
http://www.bgs.dk
informations
http://JSON.org/
http://JSONlint.com/
http://scn.sap.com

Udskrevet: 05-09-2013

- the authors home page where you find further


- JSON intruduction and standard
- JSON validator
- SAP Community Network

Side 47 af 47

You might also like