This is a test message to test the length of the message box.
Login
ABAP Tipp Konvertierung JSON nach Intern
Erstellt von Software-Heroes

ABAP Tipp - Konvertierung JSON nach Intern

In diesem kleinen Tipp gehen wir darauf ein, wie du einen JSON Stream in ein internes Format konvertierst und dann ordentlich verwenden kannst.

Werbung

Wenn du heute an die Schnittstellenlandschaft denkst, wirst du wohl oder übel nicht an OData vorbeikommen. Ebenso wenn du ein Cloud System wie Ariba oder Successfactors anbinden möchtest. All diese Systeme haben gleich, dass sie mit REST Schnittstellen kommunizieren. Doch wie verarbeitest du die Antwortdaten, wenn du mal so einen Service per HTTP Request aus ABAP ansprichst? Darauf gehen wir heute etwas genauer ein.

 

Vorbereitung

Im ersten Schritt bauen wir uns ein passendes JSON auf, dass aus verschiedenen Datentypen besteht und dazu noch intern eine Tabelle verwendet, damit wir auch mit einer tiefen/verschachtelten Struktur arbeiten können. Unser Beispielaufbau könnte also wie folgt aussehen:

 

Nachdem wir nun ein zu konvertierenden JSON String haben, wollen wir dieses auch innerhalb eines Programmlaufs konvertieren und eine interne Struktur befüllen. Diese Struktur können wir uns ebenso im ABAP aufbauen, dazu benötigen wir verschiedene Typen.

TYPES:
  BEGIN OF ts_subdata,
    key   TYPE string,
    value TYPE string,
  END OF ts_subdata,
  tt_subdata TYPE STANDARD TABLE OF ts_subdata WITH EMPTY KEY,

  BEGIN OF ts_data,
    text   TYPE string,
    number TYPE i,
    bool   TYPE abap_bool,
    table  TYPE tt_subdata,
  END OF ts_data.

 

Strukturzuweisung

Dies ist die einfachste Form der Konvertierung, du musst allerdings immer wissen wie deine Daten aussehen, um so an den Inhalt heranzukommen. Der Aufbau von verschachtelten Strukturen kann ebenso einiges an Zeit in Anspruch nehmen. Im nächsten Schritt können wir den String bereits mit der Methode Parsen.

DATA:
  ls_data TYPE ts_data.

/ui2/cl_json=>deserialize(
  EXPORTING
    json             = id_json
  CHANGING
    data             = ls_data
).

 

Wir erzeugen uns eine Struktur von unserem Zieltyp und verwenden dann die DESERIALIZE Methode der Klasse /UI2/CL_JSON, um die Konvertierung durchzuführen. Die Daten werden sauber in die Felder und die Tabelle gemappt, Element die in unserer Struktur fehlen, werden einfach übersprungen und wir können uns auf die wichtigen Inhalte konzentrieren.

 

Das Feld ADD_TEXT wird nicht gemappt, führt aber auch nicht zu einem Fehler. Das Feld BOOL wurde sauber nach ABAP_TRUE konvertiert. Damit steht uns eine einfache Art der Konvertierung zur Verfügung.

 

Generische Methode

Ebenso können wir eine Konvertierung komplett generisch durchführen, die Methode kann auch eine Referenz auf die Daten erzeugen, wenn wir keinen strukturierten Typen übergeben. Das Ergebnis einer solchen Konvertierung sieht im Eclipse Debugger wie folgt aus.

 

Auf solche komplett generischen Daten können wir nicht einfach zur Laufzeit zugreifen, da das System nicht weiß wie der Datentyp aufgebaut ist. Wir können aber über eine generische Verarbeitung auf die Daten zugreifen und diese mappen. In unserem Beispiel wollen wir einmal auf unser nicht benötigtes Element zugreifen und die Tabelle innerhalb der Struktur mappen.

DATA:
  lr_data     TYPE REF TO data,
  ld_add_text TYPE string,
  lt_subdata  TYPE tt_subdata.
FIELD-SYMBOLS:
  <lt_table> TYPE STANDARD TABLE.

/ui2/cl_json=>deserialize(
  EXPORTING
    json             = id_json
  CHANGING
    data             = lr_data
).

ASSIGN lr_data->* TO FIELD-SYMBOL(<ls_data>).

" Map the ADD_TEXT field
ASSIGN COMPONENT 'ADD_TEXT' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<ld_add>).
ASSIGN <ld_add>->* TO FIELD-SYMBOL(<ld_add_value>).
ld_add_text = <ld_add_value>.

" Map internal table 
ASSIGN COMPONENT 'TABLE' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<lt_table_ref>).
ASSIGN <lt_table_ref>->* TO <lt_table>.

LOOP AT <lt_table> ASSIGNING FIELD-SYMBOL(<ls_line>).
  ASSIGN <ls_line>->* TO FIELD-SYMBOL(<ls_line_value>).

  ASSIGN COMPONENT 'KEY' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_key>).
  ASSIGN COMPONENT 'VALUE' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_value>).

  ASSIGN <ld_key>->* TO FIELD-SYMBOL(<ld_key_value>).
  ASSIGN <ld_value>->* TO FIELD-SYMBOL(<ld_value_value>).

  INSERT VALUE #(
    key   = <ld_key_value>
    value = <ld_value_value>
  ) INTO TABLE lt_subdata.
ENDLOOP.

 

Ganz schön viel Code und viele ASSIGNs wirst du dir sicherlich denken. Jedes Element ist eine Referenz und muss doppelt gebunden werden, um an den eigentlichen Wert und die eigentlichen Daten zu gelangen. Du wirst uns sicherlich zustimmen, dass dieser Weg nicht besonders einfach ist und viele Fallen bereithält. Ebenso fehlt noch die gesamte Fehlerbehandlung im oberen Stück Quellcode, diese würde noch einmal die gleiche Anzahl Zeilen wegnehmen.

 

Beispiel

An dieser Stelle noch einmal die vollständige Beispielklasse, wie wir sie in den Beispielen verwenden.

CLASS zcl_60bs_test_json_convert DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PROTECTED SECTION.
  PRIVATE SECTION.
    TYPES:
      BEGIN OF ts_subdata,
        key   TYPE string,
        value TYPE string,
      END OF ts_subdata,
      tt_subdata TYPE STANDARD TABLE OF ts_subdata WITH EMPTY KEY,

      BEGIN OF ts_data,
        text   TYPE string,
        number TYPE i,
        bool   TYPE abap_bool,
        table  TYPE tt_subdata,
      END OF ts_data.

    METHODS:
      convert_json_with_structured
        IMPORTING
          id_json TYPE string,

      convert_json_with_reference
        IMPORTING
          id_json TYPE string.
ENDCLASS.

CLASS zcl_60bs_test_json_convert IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DATA(ld_json) = `{"text":"Some text","number":123, "bool":"TRUE", "add_text":"Text number 2", "table":[{"key":"One","value":"1"},{"key":"Two","value":"2"}]}`.

    convert_json_with_structured( ld_json ).
    convert_json_with_reference( ld_json ).
  ENDMETHOD.


  METHOD convert_json_with_structured.
    DATA:
      ls_data TYPE ts_data.

    /ui2/cl_json=>deserialize(
      EXPORTING
        json             = id_json
      CHANGING
        data             = ls_data
    ).
  ENDMETHOD.


  METHOD convert_json_with_reference.
    DATA:
      lr_data     TYPE REF TO data,
      ld_add_text TYPE string,
      lt_subdata  TYPE tt_subdata.
    FIELD-SYMBOLS:
      <lt_table> TYPE STANDARD TABLE.

    /ui2/cl_json=>deserialize(
      EXPORTING
        json             = id_json
      CHANGING
        data             = lr_data
    ).

    ASSIGN lr_data->* TO FIELD-SYMBOL(<ls_data>).

    ASSIGN COMPONENT 'ADD_TEXT' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<ld_add>).
    ASSIGN <ld_add>->* TO FIELD-SYMBOL(<ld_add_value>).
    ld_add_text = <ld_add_value>.

    ASSIGN COMPONENT 'TABLE' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<lt_table_ref>).
    ASSIGN <lt_table_ref>->* TO <lt_table>.

    LOOP AT <lt_table> ASSIGNING FIELD-SYMBOL(<ls_line>).
      ASSIGN <ls_line>->* TO FIELD-SYMBOL(<ls_line_value>).

      ASSIGN COMPONENT 'KEY' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_key>).
      ASSIGN COMPONENT 'VALUE' OF STRUCTURE <ls_line_value> TO FIELD-SYMBOL(<ld_value>).

      ASSIGN <ld_key>->* TO FIELD-SYMBOL(<ld_key_value>).
      ASSIGN <ld_value>->* TO FIELD-SYMBOL(<ld_value_value>).

      INSERT VALUE #(
        key   = <ld_key_value>
        value = <ld_value_value>
      ) INTO TABLE lt_subdata.
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

 

Fazit

Die Konvertierung eines JSON in ABAP kann sehr leicht von der Hand gehen, aber auch einiges an Kopfzerbrechen verursachen, wenn man es versucht dynamisch anzugehen. Wir empfehlen dir die Variante mit der vordefinierten Struktur, da diese viel einfacher umzusetzen ist.


Enthaltene Themen:
TippKonvertierung JSONJSON nach Intern
Kommentare (0)

ABAP Tipp - CLEAR right

Kategorie - ABAP

Richtig löschen? In diesem Artikel wollen wir uns einmal anschauen, wann es Sinn macht zu löschen und wie du effektiv vorgehen kannst.

12.05.2023

ABAP Tipp - Performance Kettensätze

Kategorie - ABAP

Schauen wir uns hier einmal die Performance beim Bilden von Kettensätzen mit DATA und FIELD-SYMBOL an. Welche Variante wird bei der Performance vorn liegen?

28.04.2023

ABAP Tipp - Adobe Formulare zu groß

Kategorie - ABAP

In diesem kleinen Tipp wollen wir uns anschauen, wieso im schlechtesten Fall Adobe Formulare größer werden, als sie eigentlich sein sollten.

18.11.2022

ABAP - ALV in 2022 noch relevant?

Kategorie - ABAP

Heute mal die scherzhafte Frage, benötigen wir im Jahr 2022 noch Reports die ALV Ausgaben erzeugen? Der Frage wollen wir in diesem Artikel einmal nachgehen.

01.07.2022

ABAP im Wandel

Kategorie - ABAP

Die Programmiersprache ABAP ist bereits seit Jahren im Wandel und modernisiert sich in verschiedenen Konzepten. In diesem Artikel schauen wir uns das einmal im Detail an.

24.06.2022