Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

ABAP JSON Handling in SAP Systems

Bridging the gap between SAP and the JSON world

Why JSON in ABAP?

In today's connected world, integrating SAP systems with external applications, APIs, and services is commonplace. JSON (JavaScript Object Notation) has become the de facto standard for lightweight data interchange. As an ABAP developer, understanding how to consume and expose data in JSON format is crucial for modern SAP integration scenarios.

SAP provides standard ABAP classes to easily handle JSON serialization (converting ABAP data into JSON strings) and deserialization (parsing JSON strings into ABAP data). This page explores these tools and techniques.

Core ABAP Classes for JSON

Over the years, SAP has introduced and refined classes for JSON processing. While older systems might still use classes like CL_SWF_JSON_SERIALIZER and CL_SWF_JSON_DESERIALIZER, the recommended and more powerful classes available in modern SAP releases (NetWeaver 7.40+ and S/4HANA) are:

  • CL_JSON_SERIALIZER: Used to convert ABAP data (variables, structures, internal tables) into a JSON string.
  • CL_JSON_PARSER: Used to parse a JSON string and populate ABAP data variables, structures, or internal tables.

These newer classes offer better performance, more features, and improved handling of complex data structures compared to their predecessors.

1. Serialization (ABAP to JSON)

Converting your ABAP data into a JSON string is straightforward using CL_JSON_SERIALIZER. The core method is SERIALIZE.

Serializing Simple Data Types & Structures

DATA: lv_string TYPE string VALUE 'Hello, JSON!',
      lv_number TYPE i     VALUE 123,
      lv_boolean TYPE abap_bool VALUE abap_true.

TYPES: BEGIN OF ty_address,
         street TYPE string,
         city   TYPE string,
       END OF ty_address.

DATA: ls_person TYPE ty_person,
      ls_address TYPE ty_address,
      lv_json_string TYPE string.

ls_address = VALUE #( street = '123 Main St' city = 'Anytown' ).
ls_person = VALUE #( name = 'Alice' age = 30 address = ls_address ). " Assuming ty_person has fields for name, age, address

TRY.
    " Serialize a simple string
    cl_json_serializer=>serialize(
      EXPORTING
        data = lv_string
      CHANGING
        json = lv_json_string
    ).
    " lv_json_string will be: "Hello, JSON!"
    " Note: Simple types are serialized as their JSON primitive equivalent

    " Serialize a structure
    cl_json_serializer=>serialize(
      EXPORTING
        data = ls_person
      CHANGING
        json = lv_json_string
    ).
    " lv_json_string will be something like:
    " {"NAME":"Alice","AGE":30,"ADDRESS":{"STREET":"123 Main St","CITY":"Anytown"}}

  CATCH cx_sy_conversion_json INTO DATA(lx_json_error).
    " Handle errors
    MESSAGE lx_json_error->get_text( ) TYPE 'E'.
ENDTRY.

Notice how ABAP structure field names are converted to uppercase JSON keys by default.

Serializing Internal Tables

Internal tables are serialized as JSON arrays of objects (one object per table row).

TYPES: BEGIN OF ty_product,
         id   TYPE string,
         name TYPE string,
         price TYPE p DECIMALS 2,
       END OF ty_product.

DATA: lt_products TYPE STANDARD TABLE OF ty_product,
      lv_json_string TYPE string.

APPEND VALUE #( id = 'P001' name = 'Laptop' price = '1200.50' ) TO lt_products.
APPEND VALUE #( id = 'P002' name = 'Keyboard' price = '75.00' ) TO lt_products.

TRY.
    cl_json_serializer=>serialize(
      EXPORTING
        data = lt_products
      CHANGING
        json = lv_json_string
    ).
    " lv_json_string will be something like:
    " [{"ID":"P001","NAME":"Laptop","PRICE":"1200.50"},{"ID":"P002","NAME":"Keyboard","PRICE":"75.00"}]
    " Note: Numeric types like P (Packed Number) might be serialized as strings by default,
    " depending on their exact definition or ABAP release.

  CATCH cx_sy_conversion_json INTO DATA(lx_json_error).
    MESSAGE lx_json_error->get_text( ) TYPE 'E'.
ENDTRY.

Serialization Options

The SERIALIZE method offers useful options via optional parameters:

  • PRETTY_PRINT: Set to abap_true to generate a human-readable, indented JSON string.
    cl_json_serializer=>serialize( EXPORTING data = ls_person pretty_print = abap_true CHANGING json = lv_json_string ).
  • CONVERT_NUMBERS_TO_STRING: Set to abap_true (default is usually false in newer releases) if you want numbers (like i, f, p) to be serialized as JSON strings instead of native JSON numbers. Useful for large numbers or precise decimal values where floating-point inaccuracies might occur.
  • INITIAL_VALUES: Controls whether fields with initial values are included in the JSON output. Default is usually cl_json_serializer=>omit_initial_values. Use cl_json_serializer=>include_initial_values to include them.
  • FIELD_NAME_TO_UPPER/TO_LOWER/AS_IS: Controls the casing of field names in the JSON output. Default is cl_json_serializer=>field_name_to_upper. Use cl_json_serializer=>field_name_as_is to retain the ABAP field name casing (requires careful naming in ABAP, e.g., using `!field_name` syntax).

2. Deserialization (JSON to ABAP)

Parsing a JSON string and filling ABAP data variables or structures is done using CL_JSON_PARSER. The main method is PARSE.

Deserializing into Simple Types & Structures

The target ABAP data structure (variable, structure, or internal table) must match the structure of the JSON data you are parsing. Field names and data types should align.

TYPES: BEGIN OF ty_address,
         street TYPE string,
         city   TYPE string,
       END OF ty_address.

TYPES: BEGIN OF ty_person,
         name    TYPE string,
         age     TYPE i,
         address TYPE ty_address,
       END OF ty_person.

DATA: lv_json_input TYPE string,
      ls_person_out TYPE ty_person.

lv_json_input = '{"name":"Bob","age":45,"address":{"street":"456 Oak Ave","city":"Newville"}}'.

TRY.
    cl_json_parser=>parse(
      EXPORTING
        json = lv_json_input
      CHANGING
        data = ls_person_out
    ).
    " ls_person_out will now contain the data from the JSON string.
    " ls_person_out-name = 'Bob'
    " ls_person_out-age = 45
    " ls_person_out-address-street = '456 Oak Ave'
    " ls_person_out-address-city = 'Newville'

  CATCH cx_sy_json_parse_error INTO DATA(lx_parse_error).
    " Handle JSON parsing syntax errors
    MESSAGE lx_parse_error->get_text( ) TYPE 'E'.
  CATCH cx_sy_assign_cast_error INTO DATA(lx_assign_error).
    " Handle mapping errors (e.g., JSON type doesn't match ABAP type)
    MESSAGE lx_assign_error->get_text( ) TYPE 'E'.
ENDTRY.

Deserializing into Internal Tables

To parse a JSON array of objects, you should deserialize it into an ABAP internal table of a structure type that matches the object structure in the JSON array.

TYPES: BEGIN OF ty_product,
         id   TYPE string,
         name TYPE string,
         price TYPE p DECIMALS 2,
       END OF ty_product.

DATA: lv_json_input TYPE string,
      lt_products_out TYPE STANDARD TABLE OF ty_product.

lv_json_input = '[{"id":"P001","name":"Laptop","price":1200.50},{"id":"P002","name":"Keyboard","price":75.00}]'.
" Note: Price is a JSON number here. ABAP P DECIMALS 2 can handle this if defined correctly.

TRY.
    cl_json_parser=>parse(
      EXPORTING
        json = lv_json_input
      CHANGING
        data = lt_products_out
    ).
    " lt_products_out will now contain two rows.

  CATCH cx_sy_json_parse_error INTO DATA(lx_parse_error).
    MESSAGE lx_parse_error->get_text( ) TYPE 'E'.
  CATCH cx_sy_assign_cast_error INTO DATA(lx_assign_error).
    MESSAGE lx_assign_error->get_text( ) TYPE 'E'.
ENDTRY.

Deserialization Options

CL_JSON_PARSER=>PARSE also has helpful options:

  • INITIAL_VALUES: Controls how to handle missing fields in the JSON input. Default is usually cl_json_parser=>omit_initial_values (missing JSON fields correspond to initial values in ABAP). Use cl_json_parser=>raise_if_missing_field to raise an exception if a JSON field expected by the ABAP structure is not found in the input.
  • FIELD_NAME_CASE: Specifies how JSON field names should be matched against ABAP field names. Options include cl_json_parser=>field_name_case_sensitive, cl_json_parser=>field_name_case_insensitive (common), cl_json_parser=>field_name_to_upper, cl_json_parser=>field_name_to_lower. Use case_insensitive or define the ABAP structure fields with the exact expected case using `!`.
  • ACCEPT_PRIMITIVE_VALUE: Useful if the JSON root element is a simple value (string, number, boolean, null) and you are parsing it into a simple ABAP variable. You need to set this to abap_true.
DATA lv_result TYPE i.
DATA lv_json_number TYPE string VALUE '123'.
TRY.
  cl_json_parser=>parse(
    EXPORTING
      json = lv_json_number
      accept_primitive_value = abap_true " Required for simple root values
    CHANGING
      data = lv_result
  ).
CATCH cx_sy_json_parse_error INTO DATA(lx).
  MESSAGE lx->get_text( ) TYPE 'E'.
ENDTRY.

Error Handling

Both SERIALIZE and PARSE methods raise exceptions of class CX_SY_CONVERSION_JSON (or its subclasses like CX_SY_JSON_PARSE_ERROR) if an error occurs. Common errors include:

  • Syntax errors in the JSON string during parsing.
  • Type mismatches between JSON values and target ABAP fields (e.g., trying to parse a JSON string into an ABAP numeric type).
  • Trying to parse a JSON array into an ABAP structure or vice versa.
  • JSON field names not matching ABAP field names (depending on case sensitivity settings).

Always wrap your calls to SERIALIZE and PARSE within TRY...CATCH blocks to gracefully handle these errors and log or inform the user.

Tips and Best Practices

  • Define ABAP Structures Clearly: Create clear and type-safe ABAP structures and table types that precisely match the expected JSON structure. Use modern ABAP syntax with inline declarations where appropriate.
  • Handle Case Sensitivity: Be mindful of case sensitivity for field names, especially during deserialization. Use the FIELD_NAME_CASE option or define ABAP fields using the ! escape character (e.g., data: begin of ls_data, "myField" type string, end of ls_data.).
  • Manage Data Types: Pay attention to how ABAP data types map to JSON types. `string` maps to string, `i`/`f` to number, `abap_bool` to boolean, initial reference/data objects to null. Packed numbers (`p`) can be tricky; consider serializing them as strings if precision is critical.
  • Use Pretty Print for Debugging: The PRETTY_PRINT option during serialization is invaluable for debugging and understanding the generated JSON output.
  • Error Reporting: In case of parsing or serialization errors, use the exception object's methods (like GET_TEXT()) to get detailed error messages.
  • Performance for Large Data: For extremely large JSON payloads, direct parsing into complex nested ABAP structures might consume significant memory. Consider alternative approaches like streaming parsers (if available or custom-built) or processing data in chunks if performance becomes an issue. However, for most typical API interactions, CL_JSON_SERIALIZER and CL_JSON_PARSER are efficient.
  • Generated Proxies: For consuming external RESTful APIs, SAP Gateway and CPI can generate ABAP proxy structures based on API specifications (like OpenAPI/Swagger), which automatically handle some of the complexity of JSON mapping.

© 2025 Your Website/Organization. All rights reserved.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool