XCO Library: Metadaten programmatisch lesen und verarbeiten

kategorie
ABAP Cloud
Veröffentlicht
autor
Johannes

Die XCO (Extension Components) Library ist eine moderne, objektorientierte API-Sammlung in ABAP Cloud, die den programmatischen Zugriff auf Repository-Objekte und Metadaten ermöglicht. Mit XCO kannst du DDIC-Objekte lesen, CDS Views analysieren, Packages verwalten und sogar Entwicklungsobjekte generieren.

Was ist XCO?

XCO steht für Extension Components und bietet eine einheitliche, cloud-fähige API für:

XCO-BereichBeschreibungHauptklasse
DDICData Dictionary-ObjekteXCO_CP_ABAP_DICTIONARY
CDSCore Data Services ViewsXCO_CP_CDS
RepositoryPackages, TransportXCO_CP_ABAP_REPOSITORY
GenerationObjektgenerierungXCO_CP_GENERATION
SystemSysteminfos, UserXCO_CP

Vorteile von XCO

  • Cloud-ready: Alle APIs sind für ABAP Cloud released (C1)
  • Fluent Interface: Lesbare, verkettbare Methodenaufrufe
  • Konsistente API: Einheitliche Patterns über alle Bereiche
  • Typsicher: Starke Typisierung mit Enumerationen

XCO für DDIC-Objekte

Datenbanktabellen lesen

Mit XCO kannst du Metadaten von Datenbanktabellen zur Laufzeit auslesen:

CLASS zcl_xco_ddic_example DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS zcl_xco_ddic_example IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
" Tabelle lesen
DATA(lo_table) = xco_cp_abap_dictionary=>database_table( 'SFLIGHT' ).
" Prüfen ob Tabelle existiert
IF lo_table->exists( ).
" Tabellen-Content (Felder) lesen
DATA(lt_fields) = lo_table->fields->all->get( ).
LOOP AT lt_fields INTO DATA(lo_field).
DATA(lv_field_name) = lo_field->name.
DATA(lv_data_element) = lo_field->content(
)->get_data_element( )->name.
out->write( |Feld: { lv_field_name } -> { lv_data_element }| ).
ENDLOOP.
" Tabellentyp ermitteln
DATA(lv_delivery_class) = lo_table->content(
)->get_delivery_class( )->value.
out->write( |Delivery Class: { lv_delivery_class }| ).
ENDIF.
ENDMETHOD.
ENDCLASS.

Datenelemente analysieren

" Datenelement lesen
DATA(lo_data_element) = xco_cp_abap_dictionary=>data_element( 'CARRID' ).
IF lo_data_element->exists( ).
" Content holen
DATA(lo_content) = lo_data_element->content( ).
" Domäne ermitteln
DATA(lv_domain) = lo_content->get_domain( )->name.
" Feldbezeichnungen lesen
DATA(ls_short_text) = lo_content->get_short_text( ).
DATA(ls_medium_text) = lo_content->get_medium_text( ).
DATA(ls_long_text) = lo_content->get_long_text( ).
out->write( |Domain: { lv_domain }| ).
out->write( |Kurztext: { ls_short_text-text }| ).
ENDIF.

Domänen mit Festwerten

" Domäne mit Festwerten lesen
DATA(lo_domain) = xco_cp_abap_dictionary=>domain( 'S_CONN_TYPE' ).
IF lo_domain->exists( ).
" Fixed Values auslesen
DATA(lt_fixed_values) = lo_domain->fixed_values->all->get( ).
LOOP AT lt_fixed_values INTO DATA(lo_fixed_value).
DATA(lv_low) = lo_fixed_value->value.
DATA(lv_description) = lo_fixed_value->content(
)->get_description( ).
out->write( |{ lv_low }: { lv_description }| ).
ENDLOOP.
ENDIF.

XCO für CDS Views

XCO ermöglicht das Lesen von CDS View-Metadaten, inklusive Felder, Assoziationen und Annotationen.

CDS View Felder auslesen

CLASS zcl_xco_cds_example DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS zcl_xco_cds_example IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
" CDS View Entity lesen
DATA(lo_view) = xco_cp_cds=>view_entity( 'I_PRODUCT' ).
IF lo_view->exists( ).
out->write( '=== CDS View: I_PRODUCT ===' ).
" Alle Felder des Views
DATA(lt_fields) = lo_view->fields->all->get( ).
out->write( |Anzahl Felder: { lines( lt_fields ) }| ).
LOOP AT lt_fields INTO DATA(lo_field).
DATA(lv_name) = lo_field->name.
DATA(lo_content) = lo_field->content( ).
" Datentyp ermitteln (wenn vorhanden)
TRY.
DATA(lv_data_element) = lo_content->get_data_element( )->name.
out->write( | { lv_name } -> { lv_data_element }| ).
CATCH cx_root.
out->write( | { lv_name } (kein Data Element)| ).
ENDTRY.
ENDLOOP.
ELSE.
out->write( 'View existiert nicht.' ).
ENDIF.
ENDMETHOD.
ENDCLASS.

Assoziationen lesen

" CDS View mit Assoziationen
DATA(lo_view) = xco_cp_cds=>view_entity( 'I_SALESORDER' ).
IF lo_view->exists( ).
" Alle Assoziationen des Views
DATA(lt_associations) = lo_view->associations->all->get( ).
LOOP AT lt_associations INTO DATA(lo_assoc).
DATA(lv_assoc_name) = lo_assoc->name.
DATA(lo_target) = lo_assoc->content( )->get_target( ).
DATA(lv_target_name) = lo_target->name.
" Kardinalität
DATA(lo_cardinality) = lo_assoc->content( )->get_cardinality( ).
DATA(lv_min) = lo_cardinality->min.
DATA(lv_max) = lo_cardinality->max.
out->write( |Association { lv_assoc_name } -> { lv_target_name }| ).
out->write( | Cardinality: [{ lv_min }..{ lv_max }]| ).
ENDLOOP.
ENDIF.

Annotationen auslesen

" Annotations eines CDS Views lesen
DATA(lo_view) = xco_cp_cds=>view_entity( 'I_BUSINESSPARTNER' ).
IF lo_view->exists( ).
" View-Level Annotations
DATA(lt_annotations) = lo_view->annotations->all->get( ).
LOOP AT lt_annotations INTO DATA(lo_annotation).
DATA(lv_anno_name) = lo_annotation->name.
TRY.
DATA(lv_value) = lo_annotation->value->get_string( ).
out->write( |@{ lv_anno_name }: { lv_value }| ).
CATCH cx_root.
out->write( |@{ lv_anno_name }: (komplexer Wert)| ).
ENDTRY.
ENDLOOP.
ENDIF.

XCO für Packages und Transport

Package-Informationen lesen

CLASS zcl_xco_package_example DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS zcl_xco_package_example IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
" Package lesen
DATA(lo_package) = xco_cp_abap_repository=>package->for( 'ZRAP_DEMO' ).
IF lo_package->exists( ).
" Package-Attribute
DATA(lo_content) = lo_package->read( ).
DATA(lv_description) = lo_content-short_description.
DATA(lv_sw_component) = lo_content-software_component.
out->write( |Package: ZRAP_DEMO| ).
out->write( |Beschreibung: { lv_description }| ).
out->write( |Software-Komponente: { lv_sw_component }| ).
" Objekte im Package auflisten
out->write( '--- Objekte im Package ---' ).
" Klassen
DATA(lt_classes) = lo_package->objects->where( xco_cp_abap=>object_type->clas
)->all->get( ).
LOOP AT lt_classes INTO DATA(lo_class).
out->write( |CLAS: { lo_class->name }| ).
ENDLOOP.
" CDS Views
DATA(lt_ddls) = lo_package->objects->where( xco_cp_abap=>object_type->ddls
)->all->get( ).
LOOP AT lt_ddls INTO DATA(lo_ddls).
out->write( |DDLS: { lo_ddls->name }| ).
ENDLOOP.
ENDIF.
ENDMETHOD.
ENDCLASS.

Transport-Informationen

" Transportauftrag lesen
DATA(lo_transport) = xco_cp_cts=>transport->for( 'NPLK900001' ).
IF lo_transport->exists( ).
DATA(lo_properties) = lo_transport->properties( ).
DATA(lv_owner) = lo_properties->get_owner( ).
DATA(lv_description) = lo_properties->get_description( ).
DATA(lv_status) = lo_properties->get_status( )->value.
out->write( |Transport: NPLK900001| ).
out->write( |Owner: { lv_owner }| ).
out->write( |Status: { lv_status }| ).
ENDIF.
" Aktuelle System-Transporte des Users
DATA(lt_transports) = xco_cp_cts=>transports->modifiable->owned_by(
xco_cp=>sy->user( )
)->where( xco_cp_transport=>type->request
)->all->get( ).
LOOP AT lt_transports INTO DATA(lo_my_transport).
out->write( |Mein Transport: { lo_my_transport->value }| ).
ENDLOOP.

Generierung von Entwicklungsobjekten

XCO ermöglicht auch die programmatische Generierung von ABAP-Objekten - ein mächtiges Feature für Generatoren und Templates.

Klasse generieren

CLASS zcl_xco_generation_example DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS generate_class
IMPORTING
iv_class_name TYPE sxco_ao_object_name
iv_package TYPE sxco_package
iv_transport TYPE sxco_transport
RAISING
cx_xco_gen_put_exception.
ENDCLASS.
CLASS zcl_xco_generation_example IMPLEMENTATION.
METHOD generate_class.
" Generation Environment für Transport
DATA(lo_environment) = xco_cp_generation=>environment->dev_system(
iv_transport
).
" PUT Operation vorbereiten
DATA(lo_put) = lo_environment->create_put_operation( ).
" Klasse spezifizieren
DATA(lo_class_spec) = lo_put->for-clas->add_object( iv_class_name
)->set_package( iv_package
)->create_form_specification( ).
" Klassen-Definition
lo_class_spec->set_short_description( 'Generated by XCO' ).
lo_class_spec->definition->set_final( ).
lo_class_spec->definition->set_create_public( ).
" Interface hinzufügen
lo_class_spec->definition->add_interface( 'IF_OO_ADT_CLASSRUN' ).
" Public Section mit Methode
lo_class_spec->definition->section-public->add_method( 'PROCESS'
)->set_returning( VALUE #(
data_type = xco_cp_abap=>type-built_in->string
) ).
" Implementierung
lo_class_spec->implementation->add_method( 'IF_OO_ADT_CLASSRUN~MAIN'
)->set_source( VALUE #(
( `out->write( 'Hello from generated class!' ).` )
) ).
lo_class_spec->implementation->add_method( 'PROCESS'
)->set_source( VALUE #(
( `result = |Processed at { sy-datum }|.` )
) ).
" Generierung ausführen
lo_put->execute( ).
ENDMETHOD.
ENDCLASS.

Interface generieren

METHOD generate_interface.
DATA(lo_environment) = xco_cp_generation=>environment->dev_system(
iv_transport
).
DATA(lo_put) = lo_environment->create_put_operation( ).
" Interface spezifizieren
DATA(lo_intf_spec) = lo_put->for-intf->add_object( 'ZIF_GENERATED'
)->set_package( 'ZPACKAGE'
)->create_form_specification( ).
lo_intf_spec->set_short_description( 'Generated Interface' ).
" Methoden hinzufügen
lo_intf_spec->add_method( 'GET_DATA'
)->set_returning( VALUE #(
data_type = xco_cp_abap=>type-built_in->string
) ).
lo_intf_spec->add_method( 'SET_DATA'
)->add_parameter( 'IV_VALUE'
)->set_importing(
)->set_data_type( xco_cp_abap=>type-built_in->string ).
lo_put->execute( ).
ENDMETHOD.

Datenbanktabelle generieren

METHOD generate_table.
DATA(lo_environment) = xco_cp_generation=>environment->dev_system(
iv_transport
).
DATA(lo_put) = lo_environment->create_put_operation( ).
" Tabelle spezifizieren
DATA(lo_table_spec) = lo_put->for-tabl-for-database_table->add_object(
'ZGENERATED_TAB'
)->set_package( 'ZPACKAGE'
)->create_form_specification( ).
lo_table_spec->set_short_description( 'Generated Table' ).
lo_table_spec->set_delivery_class( xco_cp_database_table=>delivery_class->a ).
lo_table_spec->set_data_maintenance( xco_cp_database_table=>data_maintenance->allowed ).
" Felder hinzufügen
lo_table_spec->add_field( 'CLIENT'
)->set_type( xco_cp_abap_dictionary=>data_element( 'MANDT' )
)->set_key_indicator( ).
lo_table_spec->add_field( 'ID'
)->set_type( xco_cp_abap_dictionary=>built_in_type->numc( 10 )
)->set_key_indicator( ).
lo_table_spec->add_field( 'DESCRIPTION'
)->set_type( xco_cp_abap_dictionary=>data_element( 'TEXT255' ) ).
lo_table_spec->add_field( 'CREATED_AT'
)->set_type( xco_cp_abap_dictionary=>data_element( 'TIMESTAMPL' ) ).
lo_put->execute( ).
ENDMETHOD.

Praktisches Beispiel: Dokumentationsgenerator

Dieses Beispiel zeigt, wie du mit XCO eine automatische Dokumentation für alle Objekte eines Packages generieren kannst:

CLASS zcl_package_documentation DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS generate_documentation
IMPORTING
iv_package TYPE sxco_package
RETURNING
VALUE(rt_doc) TYPE string_table.
ENDCLASS.
CLASS zcl_package_documentation IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_documentation) = generate_documentation( 'ZRAP_DEMO' ).
LOOP AT lt_documentation INTO DATA(lv_line).
out->write( lv_line ).
ENDLOOP.
ENDMETHOD.
METHOD generate_documentation.
DATA(lo_package) = xco_cp_abap_repository=>package->for( iv_package ).
IF NOT lo_package->exists( ).
APPEND |Package { iv_package } nicht gefunden.| TO rt_doc.
RETURN.
ENDIF.
APPEND |# Dokumentation Package: { iv_package }| TO rt_doc.
APPEND || TO rt_doc.
" Klassen dokumentieren
APPEND |## Klassen| TO rt_doc.
DATA(lt_classes) = lo_package->objects->where(
xco_cp_abap=>object_type->clas
)->all->get( ).
LOOP AT lt_classes INTO DATA(lo_class_obj).
DATA(lo_class) = xco_cp_abap=>class( CONV #( lo_class_obj->name ) ).
IF lo_class->exists( ).
DATA(lo_class_content) = lo_class->content( ).
DATA(lv_description) = lo_class_content->get_short_description( ).
APPEND |### { lo_class_obj->name }| TO rt_doc.
APPEND |{ lv_description }| TO rt_doc.
APPEND || TO rt_doc.
" Public Methods auflisten
DATA(lt_methods) = lo_class->definition->section-public->components->method->all->get( ).
IF lt_methods IS NOT INITIAL.
APPEND |**Public Methods:**| TO rt_doc.
LOOP AT lt_methods INTO DATA(lo_method).
APPEND |- { lo_method->name }| TO rt_doc.
ENDLOOP.
APPEND || TO rt_doc.
ENDIF.
ENDIF.
ENDLOOP.
" CDS Views dokumentieren
APPEND |## CDS Views| TO rt_doc.
DATA(lt_ddls) = lo_package->objects->where(
xco_cp_abap=>object_type->ddls
)->all->get( ).
LOOP AT lt_ddls INTO DATA(lo_ddls_obj).
DATA(lo_view) = xco_cp_cds=>view_entity( CONV #( lo_ddls_obj->name ) ).
IF lo_view->exists( ).
DATA(lt_fields) = lo_view->fields->all->get( ).
APPEND |### { lo_ddls_obj->name }| TO rt_doc.
APPEND |Felder: { lines( lt_fields ) }| TO rt_doc.
APPEND || TO rt_doc.
ENDIF.
ENDLOOP.
" Interfaces dokumentieren
APPEND |## Interfaces| TO rt_doc.
DATA(lt_intfs) = lo_package->objects->where(
xco_cp_abap=>object_type->intf
)->all->get( ).
LOOP AT lt_intfs INTO DATA(lo_intf_obj).
APPEND |- { lo_intf_obj->name }| TO rt_doc.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Best Practices

1. Existenzprüfung

Prüfe immer, ob ein Objekt existiert, bevor du darauf zugreifst:

DATA(lo_table) = xco_cp_abap_dictionary=>database_table( 'ZTABLE' ).
IF lo_table->exists( ).
" Sicher zugreifen
DATA(lo_content) = lo_table->content( ).
ENDIF.

2. Exception Handling

TRY.
DATA(lv_value) = lo_annotation->value->get_string( ).
CATCH cx_xco_runtime_exception INTO DATA(lx_error).
" Komplexe Annotation oder anderer Fehler
DATA(lv_message) = lx_error->get_text( ).
ENDTRY.

3. Fluent Interface nutzen

XCO ist für verkettete Aufrufe optimiert:

" Gut: Fluent
DATA(lt_public_methods) = xco_cp_abap=>class( 'ZCL_MYCLASS'
)->definition->section-public->components->method->all->get( ).
" Weniger gut: Viele Zwischenvariablen
DATA(lo_class) = xco_cp_abap=>class( 'ZCL_MYCLASS' ).
DATA(lo_definition) = lo_class->definition.
DATA(lo_public) = lo_definition->section-public.
" ...

4. Performance bei Massenoperationen

" Bei vielen Objekten: Erst filtern, dann lesen
DATA(lt_classes) = lo_package->objects->where(
xco_cp_abap=>object_type->clas
)->where( xco_cp_object=>object_name->range( VALUE #(
sign = 'I' option = 'CP' low = 'ZCL_*' )
) )->all->get( ).

XCO Übersicht: Wichtige Einstiegspunkte

EinstiegspunktBeschreibung
XCO_CP_ABAP_DICTIONARYDDIC: Tabellen, Views, Datenelemente, Domänen
XCO_CP_CDSCDS Views, Entities, Abstracts
XCO_CP_ABAPKlassen, Interfaces, Objekttypen
XCO_CP_ABAP_REPOSITORYPackages, Repository-Objekte
XCO_CP_CTSChange and Transport System
XCO_CP_GENERATIONObjektgenerierung
XCO_CPSystem, User, Utilities

Fazit

Die XCO Library ist ein unverzichtbares Werkzeug für fortgeschrittene ABAP Cloud-Entwicklung:

  • Metadaten-Analyse: Verstehe die Struktur deines Systems programmatisch
  • Code-Generatoren: Automatisiere die Erstellung von Entwicklungsobjekten
  • Dokumentation: Generiere automatisch technische Dokumentation
  • Tooling: Baue eigene Entwicklungswerkzeuge

Mit dem Fluent Interface und der konsistenten API-Struktur ist XCO sowohl mächtig als auch angenehm zu verwenden.

Weiterführende Artikel