
ABAP - XCO Generation and Info System
How can you use ABAP Cloud tools to generate new objects in the system and obtain information about them? Let's take a closer look at this using an example.
Table of contents
The XCO classes are helper classes that bundle various everyday functions under a public API. Further information and an overview of the XCO libraries can be found on the overview page.
Introduction
The XCO library is primarily known for its ability to generate new objects and is used in the RAP generator and for generating examples. In principle, the framework can also take over many tasks for you through automation. In our IDE Actions, we use the classes to generate a new class complete with an interface, factory, and injector. This saves a few steps during the setup and automates the task somewhat. In addition to generating, we can also obtain further information about existing objects.
Therefore, in this article, we will look at reading objects and the individual steps for creating a new class in the system.
Reading
In this chapter, we want to read and evaluate an existing class in various states.
Preparation
Before we use the XCO classes, we need a class that we can use for reading. In the class, you will find a constant and two methods. One method is static and public, the other method is private. The private method contains some content that we would like to read right away.
CLASS zcl_bs_demo_xco_broken DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
CONSTANTS c_empty TYPE string VALUE ``.
CLASS-METHODS static_access.
PRIVATE SECTION.
METHODS private_stuff.
ENDCLASS.
CLASS zcl_bs_demo_xco_broken IMPLEMENTATION.
METHOD private_stuff.
DATA(output) = `Hi from the method`.
ENDMETHOD.
METHOD static_access.
* if method.
* endif.
ENDMETHOD.
ENDCLASS.
Information
To access the class information, we create a class object using the XCO class XCO_CP_ABAP.
DATA(class) = xco_cp_abap=>class( 'ZCL_BS_DEMO_XCO_BROKEN' ).
The object offers us several methods to access various information, such as the current syntax check, the API status, whether the class exists, and other information.
Now let's perform a syntax check on the object. To do this, we call the CHECK_SYNTAX method and receive a result object. Since we are in an XCO class runner in our example, we can output the object directly to the console.
DATA(syntax) = class->check_syntax( ).
out->write_news( syntax ).
If you want to access further syntax details, various attributes are available in the object. Using MESSAGES, we can obtain corresponding error messages, and using PASSED, we get the current status of the class.
If we want to read the contents of a method in the next step, we have to perform a series of steps. First, we have to access the current implementation in the class using the IMPLEMENTATION attribute. Then we have the method returned and retrieve the contents from it. Finally, we read the source code and return a table with the current contents.
DATA(source) = class->implementation->method( 'PRIVATE_STUFF' )->content( )->get_source( ).
out->plain->write( source ).
Error
Now we change our template class ZCL_BS_DEMO_XCO_BROKEN and comment out the source code again in the STATIC_ACCESS method. We then save the content so that a current version is created in the backend. We should now have a corresponding error in the class, and activation will no longer work.
If we now run the class again and try the two steps above, we should now receive the corresponding error message from the class via CHECK_SYNTAX. The second method for reading the content still works. This gives us a simple way to validate the class syntax and generate a detailed message in case of an error.
Create
In this chapter, we will create a new class, implement an interface, create various methods, and create a local type.
Operation
In the first step, we need an operation to begin the actual creation. To do this, we use the XCO_CP_GENERATION class and create an operation using the corresponding environment and a transport request. In addition to PU, there is also PATCH if we want to update something.
DATA(operation) = xco_cp_generation=>environment->dev_system( transport_request )->create_put_operation( ).
Specification
Using this operation, we create a specification, i.e., a blueprint for a specific object. Therefore, in the operation, we say that we want to do something for a class, namely add a new object. We give the class a name, assign a package, and have the new specification returned to us so we can continue working with it.
DATA(specification) = operation->for-clas->add_object( 'ZCL_BS_DEMO_XCO_GENERATED'
)->set_package( 'ZBS_DEMO_XCO'
)->create_form_specification( ).
Using the specification, we can then set the description directly on the object.
specification->set_short_description( `Generated by ZCL_BS_DEMO_XCO_REPOSITORY` ).
Interface
To add an interface, we go through the definition and use the ADD_INTERFACE method to declare it to our class runner. To implement the method, we now need to go through the implementation and add a new method. Since we want to implement the method from the interface, we specify the name of the interface with the corresponding method. We can then directly pass the new source code that should be in the method.
specification->definition->add_interface( 'IF_OO_ADT_CLASSRUN' ).
specification->implementation->add_method( 'IF_OO_ADT_CLASSRUN~MAIN' )->set_source(
VALUE #( ( ` say_hello( name = 'Bernd' out = out ).` ) ) ).
Type
Now we would like to define a new type in the class. This should be PRIVATE and a simple type without a data element. Since types are created in the DEFINITION, we then go to the specific SECTION and add a new type with ADD_TYPE. The new type should be available under "NAME" and then receive our new type via FOR. We can then define a character with a length of 60 using TYPE and SOURCE.
specification->definition->section-private->add_type( `name` )->for( xco_cp_abap=>type-source->for( 'c LENGTH 60' ) ).
Method
Now let's define a new method as we did with the interface above. In this section, we create the private method SAY_HELLO. This time, we assign the object to a variable, as we have to perform several steps. Next, we add an importing parameter called NAME to the method, give the method a DEFAULT value, and set the type to our previously defined type. We also add an additional importing parameter to pass the OUT object from the MAIN method to our method. Finally, we add the new method and set the source code directly.
DATA(method) = specification->definition->section-private->add_method( 'SAY_HELLO' ).
method->add_importing_parameter( 'NAME' )->set_default_value( `'Herbert'` )->set_type(
xco_cp_abap=>type-source->for( 'name' ) ).
method->add_importing_parameter( 'OUT' )->set_type( xco_cp_abap=>interface( 'IF_OO_ADT_CLASSRUN_OUT' ) ).
specification->implementation->add_method( 'SAY_HELLO' )->set_source(
VALUE #( ( ` out->write( |Hello { name }| ).` ) ) ).
Activation
Now that our class definition is complete, all we need to do is execute the creation. To do this, we use the EXECUTE method in the operation; then all defined objects are created. By default, the objects are also activated at the end. If you don't want to activate the objects, but only create them inactive in the system, you can pass the SKIP_ACTIVACTION option.
* DATA(result) = operation->execute( VALUE #( ( xco_cp_generation=>put_operation_option->skip_activation ) ) ).
DATA(result) = operation->execute( ).
Result
As a result, we get a new class in the system, just as we defined it. For formatting, you should use the Pretty Printer or, better yet, the ABAP Cleaner, then you don't have to deal with manually formatting the object.
CLASS zcl_bs_demo_xco_generated DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
TYPES name TYPE c LENGTH 60.
METHODS say_hello
IMPORTING !name TYPE name DEFAULT 'Herbert'
!out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_xco_generated IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
say_hello( name = 'Bernd'
out = out ).
ENDMETHOD.
METHOD say_hello.
out->write( |Hello { name }| ).
ENDMETHOD.
ENDCLASS.
The class can also be executed directly, and we receive output in the console.
Restrictions
In our example, we use the ABAP Cloud API for the Cloud Platform (CP), which has some usage restrictions. You only have access to ABAP Cloud objects, i.e., customer-specific objects or objects released with a C1 contract. If you use an API from the Classic ABAP area, you can also read other objects with it. If you want to learn more about the differences between the various APIs, check out our Quick Guide for XCO on YouTube.
Complete example
All classes in this article can be found as commits in our repository on GitHub. This should allow you to replicate the various steps in your system. The generated class is also located in the repository; when you run the code generation, you should delete the old class first.
Conclusion
With the XCO library, you can not only generate objects, but also retrieve information about existing objects and adapt them if necessary. Today's article was just a brief insight into the topic of classes and interfaces; theoretically, there is a suitable API for every ABAP Cloud object.