
ABAP - XCO Class Runner
Wie sieht es mit der Ausführung von ABAP Klassen im Bereich von XCO aus? Schauen wir uns dazu den Class Runner genauer an.
Inhaltsverzeichnis
Die XCO Klassen sind Hilfsklassen die verschiedene Funktionen des Alltags gebündelt unter einer öffentlichen API zur Verfügung stellen. Weitere Informationen und eine Übersicht über die XCO Bibliotheken findest du auf der Übersichtsseite.
Einleitung
Mittlerweile ist ein Standard zur Ausführung von Klassen und Ausgabe der Daten in die Konsole in den ABAP Development Tools der Class Runner geworden. Vom Class Runner gibt es verschiedene Versionen und Interpretationen im Standard. Heute schauen wir uns die Implementierung für die XCO Klassen an und welche Funktionen vom Standard unterstützt werden.
Anlage
Legen wir uns dazu erst einmal eine Testklasse an, die wir für unsere Tests verwenden können. Über das Kontextmenü auf unserem Paket ZBS_DEMO_XCO oder auf dem System können wir eine neue Klasse anlegen.
Haben wir die Klasse angelegt, erwartet uns im ersten Schritt eine Fehlermeldung, da wir noch die MAIN Methode redefinieren müssen.
Mit einem Klick auf die Glühbirne im vorderen Teil oder STRG + 1 auf dem Quellcode können wir den "Quick Fix" starten und erhalten weiter Vorschläge zur Lösung des Problems.
Über "Add implementation for main" wird die Methode redefiniert und in unserer Klasse der Methodenrumpf angelegt. Die Klasse sollte im Moment so aussehen. Die Redefinition findest du im PROTECTED Bereich.
CLASS zcl_bs_demo_xco_classrun DEFINITION
PUBLIC
INHERITING FROM cl_xco_cp_adt_simple_classrun FINAL
CREATE PUBLIC.
PUBLIC SECTION.
PROTECTED SECTION.
METHODS
main REDEFINITION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_bs_demo_xco_classrun IMPLEMENTATION.
METHOD main.
ENDMETHOD.
ENDCLASS.
Ausgabe
Über die MAIN Methode erhalten wir unser OUT Objekt vom Typ IF_XCO_ADT_CLASSRUN_OUT, über dieses können wir Ausgaben in die Konsole machen. Schauen wir uns dazu das Interface erst einmal etwas näher an.
Uns stehen drei Methoden und ein Attribut zur Verfügung:
- WRITE - Generische Ausgabe von Inhalten in die Konsole, es erfolgt keine Aufbereitung von Typen.
- WRITE_NEWS - Ausgabe von Objekten mit dem Interface IF_XCO_NEWS.
- WRITE_TEXT - Ausgabe von Objekten mit dem Interface IF_XCO_PRINTABLE.
- PLAIN - Zugriff auf das Standard OUT Objekt des Class Runners, um die Standardausgaben zu erzeugen (mit Formatierung).
Implementierung
In diesem Abschnitt schauen wir uns die unterschiedlichen Methoden im Detail an und wie sich diese bei der Ausgabe verhalten.
WRITE
Die einfachste Methode ist WRITE, die alle Daten entgegennimmt. Dazu definieren wir uns ein Datum, einen String, eine Tabelle von Strings und eine strukturierte Tabelle. Diese übergeben wir dann an die Methode und schauen uns die Ausgabe an.
DATA(simple_date) = CONV d( '20250228' ).
DATA(my_string) = `ABAP can handle long texts as string!`.
DATA(my_strings) = VALUE string_table( ( `ABAP can` ) ( `handle` ) ( `long texts` ) ( `as string!` ) ).
DATA(persons) = get_persons( ).
out->write( simple_date ).
out->write( my_string ).
out->write( my_strings ).
out->write( persons[ 1 ] ).
out->write( persons ).
Die Daten werden jeweils in einer Zeile ausgegeben. Es erfolgt keine Ausgabeformatierung des Datums und die Tabellen/Strukturen werden als JSON Objekt ausgegeben.
WRITE_NEWS
Die Methode dient zur Erzeugung von Ausgaben über Objekte mit integriertem Interface IF_XCO_NEWS. Das Interface gibt eine Liste von Einzelmeldungen zurück, bei denen dann die Methode GET_TEXT aufgerufen wird. Damit wird die Methode vor allem zur Ausgabe von
MESSAGE w001(zbs_demo_xco) WITH 'Method' 'Message' INTO DATA(dummy_message).
DATA(xco_message) = xco_cp=>sy->message( ).
out->write_news( xco_message ).
Die Ausgabe der Nachricht erfolgt dann als einfacher Text und ohne Angabe des Typs oder weiterer Informationen zur Nachricht.
WRITE_TEXT
Die Methode WRITE_TEXT gibt Daten für XCO Objekte aus. Besitzt die Klasse das Interface IF_XCO_PRINTABLE, können die Ausgaben entsprechend aufbereitet und ausgegeben werden. Dazu erzeugen wir einige XCO Objekte, wie Strings oder Daten.
DATA(xco_string) = xco_cp=>string( `ABAP can handle long texts as string!` ).
DATA(xco_strings) = xco_cp=>strings( VALUE #( ( `ABAP can` ) ( `handle` ) ( `long texts` ) ( `as string!` ) ) ).
DATA(xco_date) = xco_cp=>sy->date( ).
DATA(xco_moment) = xco_cp=>sy->moment( ).
out->write( xco_string ).
out->write( xco_strings ).
out->write( xco_date ).
out->write( xco_moment ).
Bei der Ausgabe wird dir auffallen, dass die Datumstypen keine Standardausgabe liefern, sondern nur als Objektreferenz aufgeführt werden. Dazu müssen wir Objekte mit Ausgabe erzeugen, wie zum Beispiel STRING Objekte mit der Methode AS.
out->write( xco_date->as( xco_cp_time=>format->abap ) ).
out->write( xco_moment->as( xco_cp_time=>format->abap ) ).
Die gesamte Ausgabe des Abschnitts würde dann wie folgt aussehen:
PLAIN
Über das PLAIN Attribut des OUT Objekts haben wir Zugriff auf das Standardobjekt des klassischen Class Runners. Über WRITE können wir Inhalte in die Konsole ausgeben.
out->plain->write( get_persons( ) ).
Mit GET können wir uns die aktuelle Ausgabe für die Konsole als String zurückgeben lassen. Rufst du die Methode auf, wird der aktuelle Ausgabepuffer zurückgesetzt und es wird nichts in die Konsole ausgegeben.
DATA(console_output_raw) = out->plain->get( ).
Möchtest du zum Beispiel die Daten für eine Tabelle wieder in einer formatierten Form ausgeben, dann kannst du das einfach über das Standardobjekt machen.
Stabilität
Schauen wir uns zum Abschluss noch die Stabilität des Class Runners an. Lösen wir normalerweise eine Ausnahme aus und behandeln diese nicht, kommt es zu einem Abbruch mit Dump. Dazu implementieren wir die folgende Logik in einer eigenen Methode:
DATA(result_in_error) = 12 / 0.
Wenn wir die Logik ausführen, kommt es nicht zu einem Abbruch, sondern es wird ein Fehler im Log ausgegeben. Wenn du tiefer in den Standard abtauchst, wirst du einen TRY/CATCH für CX_ROOT finden, der alle abfangbaren Ausnahmen fängt und ausgibt.
Vollständiges Beispiel
Das vollständige Beispiel der Implementierung findest du noch einmal an dieser Stelle. Zusätzlich findest du im GitHub Repository die weiteren Beispiele aus dem Bereich XCO. Über den Commit findest du die gemachten Änderungen des Artikels.
CLASS zcl_bs_demo_xco_classrun DEFINITION
PUBLIC
INHERITING FROM cl_xco_cp_adt_simple_classrun FINAL
CREATE PUBLIC.
PUBLIC SECTION.
PROTECTED SECTION.
METHODS
main REDEFINITION.
PRIVATE SECTION.
TYPES: BEGIN OF person,
user_id TYPE c LENGTH 12,
name TYPE string,
birthday TYPE d,
size_in_cm TYPE i,
END OF person.
TYPES persons TYPE STANDARD TABLE OF person WITH EMPTY KEY.
METHODS output_with_write
IMPORTING !out TYPE REF TO if_xco_adt_classrun_out.
METHODS output_with_write_text
IMPORTING !out TYPE REF TO if_xco_adt_classrun_out.
METHODS output_with_write_news
IMPORTING !out TYPE REF TO if_xco_adt_classrun_out.
METHODS use_plain_object
IMPORTING !out TYPE REF TO if_xco_adt_classrun_out.
METHODS get_persons
RETURNING VALUE(result) TYPE persons.
METHODS crash_me.
ENDCLASS.
CLASS zcl_bs_demo_xco_classrun IMPLEMENTATION.
METHOD main.
output_with_write( out ).
output_with_write_text( out ).
output_with_write_news( out ).
use_plain_object( out ).
crash_me( ).
ENDMETHOD.
METHOD get_persons.
RETURN VALUE persons( ( user_id = 'P01' name = `Phillipp Kohl` birthday = '19850522' size_in_cm = 174 )
( user_id = 'P02' name = `Ruth Z. Robinson` birthday = '19850107' size_in_cm = 168 )
( user_id = 'P03' name = `James S. Richardson` birthday = '19921102' size_in_cm = 186 ) ).
ENDMETHOD.
METHOD output_with_write.
DATA(simple_date) = CONV d( '20250228' ).
DATA(my_string) = `ABAP can handle long texts as string!`.
DATA(my_strings) = VALUE string_table( ( `ABAP can` ) ( `handle` ) ( `long texts` ) ( `as string!` ) ).
DATA(persons) = get_persons( ).
out->write( simple_date ).
out->write( my_string ).
out->write( my_strings ).
out->write( persons[ 1 ] ).
out->write( persons ).
ENDMETHOD.
METHOD output_with_write_text.
DATA(xco_string) = xco_cp=>string( `ABAP can handle long texts as string!` ).
DATA(xco_strings) = xco_cp=>strings( VALUE #( ( `ABAP can` ) ( `handle` ) ( `long texts` ) ( `as string!` ) ) ).
DATA(xco_date) = xco_cp=>sy->date( ).
DATA(xco_moment) = xco_cp=>sy->moment( ).
out->write( xco_string ).
out->write( xco_strings ).
out->write( xco_date ).
out->write( xco_moment ).
out->write( xco_date->as( xco_cp_time=>format->abap ) ).
out->write( xco_moment->as( xco_cp_time=>format->abap ) ).
ENDMETHOD.
METHOD output_with_write_news.
MESSAGE w001(zbs_demo_xco) WITH 'Method' 'Message' INTO DATA(dummy_message).
DATA(xco_message) = xco_cp=>sy->message( ).
out->write_news( xco_message ).
ENDMETHOD.
METHOD use_plain_object.
out->plain->write( get_persons( ) ).
* DATA(console_output_raw) = out->plain->get( ).
ENDMETHOD.
METHOD crash_me.
DATA(result_in_error) = 12 / 0.
ENDMETHOD.
ENDCLASS.
Fazit
Der Class Runner aus dem Bereich XCO bietet den Vorteil der Stabilität und dass die Main Methode nicht aus anderen Entwicklungen aufgerufen werden kann und es damit vielleicht zu Fehlern kommt. Zusätzlich kannst du über die Ausgabe viele XCO Objekte ausgeben, deren Aufbereitung sonst etwas schwieriger sein könnte. Trotzdem bleibt die Ausgabe noch ausbaufähig, wenn es um Standardtypen wie Datum oder Moment geht.
Quellen:
SAP Help - XCO ADT