ABAP JSON Verarbeitung: Serialisierung und Deserialisierung

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

JSON (JavaScript Object Notation) ist das Standardformat für REST-APIs und moderne Integrationen. ABAP bietet mehrere Möglichkeiten zur JSON-Verarbeitung: /ui2/cl_json, XCO-Bibliotheken und native ABAP-Transformation.

Übersicht der Methoden

MethodeVerfügbarkeitEmpfehlung
/ui2/cl_jsonAb 7.40Einfach, weit verbreitet
XCO (Cloud)ABAP CloudModern, typsicher
Simple TransformationAllePerformant, mehr Aufwand
sXMLAlleLow-Level

/ui2/cl_json – Der Klassiker

1. Struktur zu JSON (Serialisierung)

TYPES: BEGIN OF ty_customer,
id TYPE i,
name TYPE string,
email TYPE string,
active TYPE abap_bool,
END OF ty_customer.
DATA: ls_customer TYPE ty_customer.
ls_customer = VALUE #(
id = 1001
name = 'Max Mustermann'
email = 'max@example.com'
active = abap_true
).
" Struktur zu JSON konvertieren
DATA(lv_json) = /ui2/cl_json=>serialize(
data = ls_customer
compress = abap_true " Keine Nullwerte/leere Felder
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
WRITE: / lv_json.
" {"id":1001,"name":"Max Mustermann","email":"max@example.com","active":true}

2. JSON zu Struktur (Deserialisierung)

DATA: lv_json TYPE string.
DATA: ls_customer TYPE ty_customer.
lv_json = '{"id":1001,"name":"Max Mustermann","email":"max@example.com","active":true}'.
" JSON zu Struktur konvertieren
/ui2/cl_json=>deserialize(
EXPORTING
json = lv_json
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
CHANGING
data = ls_customer
).
WRITE: / 'ID:', ls_customer-id.
WRITE: / 'Name:', ls_customer-name.
WRITE: / 'E-Mail:', ls_customer-email.

3. Interne Tabelle zu JSON

DATA: lt_customers TYPE TABLE OF ty_customer.
lt_customers = VALUE #(
( id = 1 name = 'Müller' email = 'mueller@test.de' active = abap_true )
( id = 2 name = 'Schmidt' email = 'schmidt@test.de' active = abap_true )
( id = 3 name = 'Weber' email = 'weber@test.de' active = abap_false )
).
DATA(lv_json) = /ui2/cl_json=>serialize(
data = lt_customers
compress = abap_true
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
WRITE: / lv_json.
" [{"id":1,"name":"Müller",...},{"id":2,...},{"id":3,...}]

4. JSON-Array zu Tabelle

DATA: lv_json TYPE string.
DATA: lt_customers TYPE TABLE OF ty_customer.
lv_json = '[{"id":1,"name":"A"},{"id":2,"name":"B"},{"id":3,"name":"C"}]'.
/ui2/cl_json=>deserialize(
EXPORTING json = lv_json
CHANGING data = lt_customers
).
LOOP AT lt_customers INTO DATA(ls_cust).
WRITE: / ls_cust-id, ls_cust-name.
ENDLOOP.

5. Pretty-Name Optionen

DATA: ls_data TYPE ty_customer.
" Original ABAP-Namen (UPPERCASE)
DATA(lv_json1) = /ui2/cl_json=>serialize(
data = ls_data
pretty_name = /ui2/cl_json=>pretty_mode-none
).
" {"ID":1001,"NAME":"Max",...}
" camelCase
DATA(lv_json2) = /ui2/cl_json=>serialize(
data = ls_data
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
" {"id":1001,"name":"Max",...}
" Lowercase mit Unterstrichen
DATA(lv_json3) = /ui2/cl_json=>serialize(
data = ls_data
pretty_name = /ui2/cl_json=>pretty_mode-low_case
).
" {"id":1001,"name":"Max",...}

6. Verschachtelte Strukturen

TYPES: BEGIN OF ty_address,
street TYPE string,
city TYPE string,
zip 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: ls_person TYPE ty_person.
ls_person = VALUE #(
name = 'Max'
age = 30
address = VALUE #(
street = 'Hauptstraße 1'
city = 'Berlin'
zip = '10115'
)
).
DATA(lv_json) = /ui2/cl_json=>serialize(
data = ls_person
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
" {"name":"Max","age":30,"address":{"street":"Hauptstraße 1","city":"Berlin","zip":"10115"}}

7. Formatierte Ausgabe (Pretty Print)

DATA(lv_json) = /ui2/cl_json=>serialize(
data = ls_customer
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
format_output = abap_true " Eingerückt/formatiert
).
" {
" "id": 1001,
" "name": "Max Mustermann",
" "email": "max@example.com"
" }

8. Generisches Parsen (ohne Typ)

DATA: lv_json TYPE string.
DATA: lr_data TYPE REF TO data.
FIELD-SYMBOLS: <data> TYPE any.
lv_json = '{"name":"Max","age":30,"items":[1,2,3]}'.
" Generisch parsen
/ui2/cl_json=>deserialize(
EXPORTING json = lv_json
CHANGING data = lr_data
).
" Ergebnis ist eine dynamische Struktur
ASSIGN lr_data->* TO <data>.

9. Name-Mapping

TYPES: BEGIN OF ty_abap_struct,
customer_id TYPE i,
customer_name TYPE string,
END OF ty_abap_struct.
DATA: ls_data TYPE ty_abap_struct.
" JSON mit anderen Feldnamen
DATA: lv_json TYPE string VALUE '{"customerId":1,"customerName":"Test"}'.
" Name-Mapping über PRETTY_NAME
/ui2/cl_json=>deserialize(
EXPORTING
json = lv_json
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
CHANGING
data = ls_data
).
WRITE: / ls_data-customer_id, ls_data-customer_name.

XCO – ABAP Cloud

10. XCO JSON Serialisierung

" Nur in ABAP Cloud / Steampunk verfügbar
DATA: ls_customer TYPE ty_customer.
ls_customer = VALUE #( id = 1 name = 'Test' email = 'test@test.de' ).
" Serialisieren
DATA(lv_json) = xco_cp_json=>data->from_abap( ls_customer
)->apply( VALUE #(
( xco_cp_json=>transformation->camel_case )
)
)->to_string( ).
" Deserialisieren
xco_cp_json=>data->from_string( lv_json
)->apply( VALUE #(
( xco_cp_json=>transformation->underscore_case )
)
)->write_to( REF #( ls_customer ) ).

Simple Transformation

11. JSON mit Simple Transformation

" Transformation Z_JSON_CUSTOMER erstellen (STRANS)
" <?sap.transform simple?>
" <tt:transform xmlns:tt="http://www.sap.com/transformation-templates"
" template="main">
" <tt:root name="CUSTOMER"/>
" <tt:template>
" <object>
" <str name="id"><tt:value ref="CUSTOMER.ID"/></str>
" <str name="name"><tt:value ref="CUSTOMER.NAME"/></str>
" </object>
" </tt:template>
" </tt:transform>
DATA: ls_customer TYPE ty_customer,
lv_json TYPE string.
ls_customer = VALUE #( id = 1 name = 'Max' ).
" ABAP zu JSON
CALL TRANSFORMATION z_json_customer
SOURCE customer = ls_customer
RESULT XML lv_json
OPTIONS data_refs = 'embedded'.
" JSON zu ABAP
CALL TRANSFORMATION z_json_customer
SOURCE XML lv_json
RESULT customer = ls_customer.

Praktische Beispiele

12. REST-API Aufruf

DATA: lv_response TYPE string,
ls_result TYPE ty_api_response.
" HTTP-Request
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = cl_http_destination_provider=>create_by_url( 'https://api.example.com' )
).
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_uri_path( '/api/customers/1' ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>get ).
lv_response = lo_response->get_text( ).
" JSON Response parsen
/ui2/cl_json=>deserialize(
EXPORTING json = lv_response
CHANGING data = ls_result
).
lo_client->close( ).

13. JSON POST-Request

TYPES: BEGIN OF ty_request,
action TYPE string,
payload TYPE string,
END OF ty_request.
DATA: ls_request TYPE ty_request.
ls_request = VALUE #(
action = 'create'
payload = 'test data'
).
" Request-Body erstellen
DATA(lv_json_body) = /ui2/cl_json=>serialize(
data = ls_request
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
" HTTP POST
DATA(lo_client) = cl_web_http_client_manager=>create_by_http_destination(
i_destination = cl_http_destination_provider=>create_by_url( 'https://api.example.com' )
).
DATA(lo_request) = lo_client->get_http_request( ).
lo_request->set_uri_path( '/api/process' ).
lo_request->set_header_field( i_name = 'Content-Type' i_value = 'application/json' ).
lo_request->set_text( lv_json_body ).
DATA(lo_response) = lo_client->execute( if_web_http_client=>post ).

14. Fehlerbehandlung

DATA: lv_json TYPE string VALUE '{"invalid json'.
DATA: ls_data TYPE ty_customer.
TRY.
/ui2/cl_json=>deserialize(
EXPORTING json = lv_json
CHANGING data = ls_data
).
CATCH cx_sy_move_cast_error INTO DATA(lx_error).
WRITE: / 'JSON-Parsing-Fehler:', lx_error->get_text( ).
ENDTRY.

15. Datum/Zeit in JSON

TYPES: BEGIN OF ty_event,
name TYPE string,
event_date TYPE d,
event_time TYPE t,
timestamp TYPE timestamp,
END OF ty_event.
DATA: ls_event TYPE ty_event.
ls_event = VALUE #(
name = 'Meeting'
event_date = sy-datum
event_time = sy-uzeit
timestamp = utclong_current( )
).
" Standard: Datum als YYYYMMDD
DATA(lv_json) = /ui2/cl_json=>serialize(
data = ls_event
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
" Für ISO-Format: Eigene Konvertierung nötig

16. Arrays von primitiven Typen

DATA: lt_ids TYPE TABLE OF i.
lt_ids = VALUE #( ( 1 ) ( 2 ) ( 3 ) ( 4 ) ( 5 ) ).
DATA(lv_json) = /ui2/cl_json=>serialize( data = lt_ids ).
WRITE: / lv_json. " [1,2,3,4,5]
" Zurück
DATA: lt_parsed TYPE TABLE OF i.
/ui2/cl_json=>deserialize(
EXPORTING json = lv_json
CHANGING data = lt_parsed
).

17. Null-Werte behandeln

TYPES: BEGIN OF ty_nullable,
name TYPE string,
value TYPE i,
END OF ty_nullable.
DATA: ls_data TYPE ty_nullable.
ls_data = VALUE #( name = 'Test' ). " value bleibt initial (0)
" Mit compress = true: Initialwerte weglassen
DATA(lv_compressed) = /ui2/cl_json=>serialize(
data = ls_data
compress = abap_true
).
" {"name":"Test"}
" Ohne compress: Alle Felder
DATA(lv_full) = /ui2/cl_json=>serialize(
data = ls_data
compress = abap_false
).
" {"name":"Test","value":0}

18. Boolean-Werte

TYPES: BEGIN OF ty_flags,
enabled TYPE abap_bool,
visible TYPE abap_bool,
END OF ty_flags.
DATA: ls_flags TYPE ty_flags.
ls_flags = VALUE #(
enabled = abap_true
visible = abap_false
).
DATA(lv_json) = /ui2/cl_json=>serialize(
data = ls_flags
pretty_name = /ui2/cl_json=>pretty_mode-camel_case
).
WRITE: / lv_json. " {"enabled":true,"visible":false}

Tipps für API-Integration

" 1. Typen definieren passend zur API
TYPES: BEGIN OF ty_api_error,
code TYPE string,
message TYPE string,
END OF ty_api_error.
TYPES: BEGIN OF ty_api_response,
success TYPE abap_bool,
data TYPE ty_customer,
error TYPE ty_api_error,
END OF ty_api_response.
" 2. Response verarbeiten
DATA(lv_status) = lo_response->get_status( )-code.
DATA(lv_body) = lo_response->get_text( ).
DATA: ls_response TYPE ty_api_response.
/ui2/cl_json=>deserialize(
EXPORTING json = lv_body
CHANGING data = ls_response
).
IF ls_response-success = abap_true.
" Erfolg verarbeiten
ELSE.
" Fehler behandeln
WRITE: / 'Fehler:', ls_response-error-message.
ENDIF.

Wichtige Hinweise / Best Practice

  • /ui2/cl_json ist der Standard für JSON in klassischem ABAP.
  • pretty_name für Namenskonvertierung (camelCase, lowercase).
  • compress = abap_true entfernt leere/initiale Felder.
  • Für ABAP Cloud: XCO-Bibliotheken verwenden.
  • Simple Transformations für maximale Performance.
  • ABAP-Feldnamen mit Unterstrichen werden zu camelCase konvertiert.
  • Testen Sie JSON-Strukturen mit Online-Tools (jsonlint.com).
  • Definieren Sie passende ABAP-Typen für API-Responses.
  • Fehlerbehandlung mit TRY-CATCH für ungültiges JSON.
  • Boolean: abap_true/abap_false wird zu true/false.