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-Bereich | Beschreibung | Hauptklasse |
|---|---|---|
| DDIC | Data Dictionary-Objekte | XCO_CP_ABAP_DICTIONARY |
| CDS | Core Data Services Views | XCO_CP_CDS |
| Repository | Packages, Transport | XCO_CP_ABAP_REPOSITORY |
| Generation | Objektgenerierung | XCO_CP_GENERATION |
| System | Systeminfos, User | XCO_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 lesenDATA(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 lesenDATA(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 AssoziationenDATA(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 lesenDATA(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 lesenDATA(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 UsersDATA(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: FluentDATA(lt_public_methods) = xco_cp_abap=>class( 'ZCL_MYCLASS' )->definition->section-public->components->method->all->get( ).
" Weniger gut: Viele ZwischenvariablenDATA(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 lesenDATA(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
| Einstiegspunkt | Beschreibung |
|---|---|
XCO_CP_ABAP_DICTIONARY | DDIC: Tabellen, Views, Datenelemente, Domänen |
XCO_CP_CDS | CDS Views, Entities, Abstracts |
XCO_CP_ABAP | Klassen, Interfaces, Objekttypen |
XCO_CP_ABAP_REPOSITORY | Packages, Repository-Objekte |
XCO_CP_CTS | Change and Transport System |
XCO_CP_GENERATION | Objektgenerierung |
XCO_CP | System, 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.