This commit is contained in:
danrega
2024-12-19 17:25:10 +01:00
parent c60e30931a
commit 0b2e7aae9b
2 changed files with 523 additions and 224 deletions

View File

@@ -20,7 +20,6 @@
- [Defining Parameters as Optional](#defining-parameters-as-optional)
- [Defining Input Parameters as Preferred](#defining-input-parameters-as-preferred)
- [Constructors](#constructors)
- [Example for Method Definitions](#example-for-method-definitions)
- [Working with Objects and Components](#working-with-objects-and-components)
- [Declaring Object Reference Variables](#declaring-object-reference-variables)
- [Creating Objects](#creating-objects)
@@ -47,6 +46,7 @@
- [Events](#events)
- [Examples for Design Patterns: Factory Methods and Singletons](#examples-for-design-patterns-factory-methods-and-singletons)
- [Class-Based Exceptions](#class-based-exceptions)
- [ABAP Doc Comments](#abap-doc-comments)
- [More Information](#more-information)
- [Executable Example](#executable-example)
@@ -525,6 +525,78 @@ ENDCLASS.
section. Note that you must create an instance of a class first before using instance methods.
- `CLASS-METHODS` and `METHODS` can be followed by a colon to list one or more methods, separated by commas, or without a colon to declare a single method.
The following code snippet shows (which anticipates aspects described in the following sections, such as specifying the method signature, constructors etc.) multiple method definitions in the public section of a global class. Most of the formal
parameters of the demo methods below are defined by just using the
parameter name. This means passing by reference (returning parameters
require to be passed by value).
``` abap
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS: inst_meth1, "instance methods
inst_meth2 IMPORTING a TYPE string,
inst_meth3 IMPORTING b TYPE i
EXPORTING c TYPE i,
inst_meth4 IMPORTING d TYPE string
RETURNING VALUE(e) TYPE string,
"Note that method declarations should be done with care. An example
"as follows may not be advisable, e.g. specifying multiple output
"parameters (both exporting and returning parameters for a method).
"As is valid for all examples in the cheat sheet, the focus is on
"syntax options.
inst_meth5 IMPORTING f TYPE i
EXPORTING g TYPE i
CHANGING h TYPE string
RETURNING VALUE(i) TYPE i
RAISING cx_sy_zerodivide,
constructor IMPORTING j TYPE i. "instance constructor with importing parameter
CLASS-METHODS: stat_meth1, "static methods
stat_meth2 IMPORTING k TYPE i
EXPORTING l TYPE i,
class_constructor, "static constructor
"Options of formal parameter definitions
stat_meth3 IMPORTING VALUE(m) TYPE i, "pass by value
stat_meth4 IMPORTING REFERENCE(n) TYPE i, "pass by reference
stat_meth5 IMPORTING o TYPE i, "same as n; the specification of REFERENCE(...) is optional
stat_meth6 RETURNING VALUE(p) TYPE i, "pass by value once more (note: it's the only option for returning parameters)
"OPTIONAL/DEFAULT additions
stat_meth7 IMPORTING q TYPE i DEFAULT 123
r TYPE i OPTIONAL,
"The examples above use a complete type for
"the parameter specification. Generic types
"are possible.
stat_meth8 IMPORTING s TYPE any "Any data type
t TYPE any table "Any internal table type
u TYPE clike. "Character-like types (c, n, string, d, t and character-like flat structures)
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD inst_meth1.
...
ENDMETHOD.
... "Further method implementations. Note that all declared methods must go here.
ENDCLASS.
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
#### Parameter Interface
@@ -955,6 +1027,100 @@ ENDCLASS.
- [`DEFAULT`](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abapmethods_parameters.htm#!ABAP_ONE_ADD@1@): Also makes the passing of an actual parameter optional. However, when using this addition, as the name implies, a default value is set.
- In the method implementations you may want to check whether an actual parameter was passed. You can use predicate expressions using `IS SUPPLIED`. See the example further down.
The following example (which anticipates aspects described in the following sections, such as calling methods) includes three methods that specify optional parameters. The methods are called with and without providing actual parameters. The method implementations include the use of the predicate expression `IS SUPPLIED` with `IF` statements and the `COND` operator. The console output of the example, run with F9, is as follows:
```
meth1_result_a
The parameter is not supplied. Initial value: "0".
meth1_result_b
The parameter is supplied. Value: "2".
meth2_result_a
The parameter is not supplied. Default value: "1".
meth2_result_b
The parameter is supplied. Value: "3".
meth3_result_b
num1: "4" / num2 (is not supplied; initial value): "0" / num3 (is not supplied; default value): "1"
meth3_result_c
num1: "5" / num2 (is supplied): "6" / num3 (is not supplied; default value): "1"
meth3_result_d
num1: "7" / num2 (is not supplied; initial value): "0" / num3 (is supplied): "8"
```
```abap
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS meth1 IMPORTING num TYPE i OPTIONAL
RETURNING VALUE(str) TYPE string.
METHODS meth2 IMPORTING num TYPE i DEFAULT 1
RETURNING VALUE(str) TYPE string.
METHODS meth3 IMPORTING num1 TYPE i
num2 TYPE i OPTIONAL
num3 TYPE i DEFAULT 1
RETURNING VALUE(str) TYPE string.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(meth1_result_a) = meth1( ).
DATA(meth1_result_b) = meth1( 2 ).
DATA(meth2_result_a) = meth2( ).
DATA(meth2_result_b) = meth2( 3 ).
"The commented out statement is not possible as there is one
"non-optional parameter.
"DATA(meth3_result_a) = meth3( ).
DATA(meth3_result_b) = meth3( 4 ).
DATA(meth3_result_c) = meth3( num1 = 5 num2 = 6 ).
DATA(meth3_result_d) = meth3( num1 = 7 num3 = 8 ).
out->write( data = meth1_result_a name = `meth1_result_a` ).
out->write( data = meth1_result_b name = `meth1_result_b` ).
out->write( data = meth2_result_a name = `meth2_result_a` ).
out->write( data = meth2_result_b name = `meth2_result_b` ).
out->write( data = meth3_result_b name = `meth3_result_b` ).
out->write( data = meth3_result_c name = `meth3_result_c` ).
out->write( data = meth3_result_d name = `meth3_result_d` ).
ENDMETHOD.
METHOD meth1.
IF num IS SUPPLIED.
str = |The parameter is supplied. Value: "{ num }".|.
ELSE.
str = |The parameter is not supplied. Initial value: "{ num }".|.
ENDIF.
ENDMETHOD.
METHOD meth2.
str = COND #( WHEN num IS SUPPLIED THEN |The parameter is supplied. Value: "{ num }".|
ELSE |The parameter is not supplied. Default value: "{ num }".| ).
ENDMETHOD.
METHOD meth3.
str = |num1: "{ num1 }" / |.
str &&= |{ COND #( WHEN num2 IS SUPPLIED THEN |num2 (is supplied): "{ num2 }"|
ELSE |num2 (is not supplied; initial value): "{ num2 }"| ) } / |.
str &&= |{ COND #( WHEN num3 IS SUPPLIED THEN |num3 (is supplied): "{ num3 }"|
ELSE |num3 (is not supplied; default value): "{ num3 }"| ) } |.
ENDMETHOD.
ENDCLASS.
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
#### Defining Input Parameters as Preferred
@@ -1142,75 +1308,6 @@ ENDCLASS.
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
#### Example for Method Definitions
The following snippet shows
multiple method definitions in the public section of a global class. Most of the formal
parameters of the demo methods below are defined by just using the
parameter name. This means passing by reference (returning parameters
require to be passed by value).
``` abap
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS: inst_meth1, "instance methods
inst_meth2 IMPORTING a TYPE string,
inst_meth3 IMPORTING b TYPE i
EXPORTING c TYPE i,
inst_meth4 IMPORTING d TYPE string
RETURNING VALUE(e) TYPE string,
inst_meth5 IMPORTING f TYPE i
EXPORTING g TYPE i
CHANGING h TYPE string
RETURNING VALUE(i) TYPE i
RAISING cx_sy_zerodivide,
constructor IMPORTING j TYPE i. "instance constructor with importing parameter
CLASS-METHODS: stat_meth1, "static methods
stat_meth2 IMPORTING k TYPE i
EXPORTING l TYPE i,
class_constructor, "static constructor
"Options of formal parameter definitions
stat_meth3 IMPORTING VALUE(m) TYPE i, "pass by value
stat_meth4 IMPORTING REFERENCE(n) TYPE i, "pass by reference
stat_meth5 IMPORTING o TYPE i, "same as n; the specification of REFERENCE(...) is optional
stat_meth6 RETURNING VALUE(p) TYPE i, "pass by value once more (note: it's the only option for returning parameters)
"OPTIONAL/DEFAULT additions
stat_meth7 IMPORTING q TYPE i DEFAULT 123
r TYPE i OPTIONAL,
"The examples above use a complete type for
"the parameter specification. Generic types
"are possible.
stat_meth8 IMPORTING s TYPE any "Any data type
t TYPE any table "Any internal table type
u TYPE clike. "Character-like types (c, n, string, d, t and character-like flat structures)
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD inst_meth1.
...
ENDMETHOD.
... "Further method implementations. Note that all declared methods must go here.
ENDCLASS.
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
## Working with Objects and Components
@@ -1267,15 +1364,17 @@ DATA(ref2) = NEW some_class( ). "Reference variable declared inline, explic
"instance constructor. If a class has, actual parameters must be provided.
DATA(ref_mand_param) = NEW another_class( ip1 = ... ip2 = ... ).
"Older syntax
"CREATE OBJECT ref3. "Type derived from already declared ref3
"CREATE OBJECT ref4 TYPE some_class. "Corresponds to the result of the expression above
"Older syntax, replaced by NEW operator
"However, the CREATE OBJECT is required in dynamic object creation.
CREATE OBJECT ref3. "Type derived from already declared ref3
CREATE OBJECT ref4 TYPE some_class. "Corresponds to the result of the expression above
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
### Working with Reference Variables
Some examples for working with reference variables:
This section covers some aspects of working with reference variables.
**Assigning Reference Variables**
@@ -1716,6 +1815,7 @@ CLASS zcl_some_class DEFINITION
RETURNING VALUE(ref) TYPE REF TO zcl_some_class.
METHODS add_space RETURNING VALUE(ref) TYPE REF TO zcl_some_class.
METHODS add_period RETURNING VALUE(ref) TYPE REF TO zcl_some_class.
METHODS return_text RETURNING VALUE(str) TYPE string.
METHODS display_text IMPORTING cl_run_ref TYPE REF TO if_oo_adt_classrun_out.
DATA text TYPE string.
PROTECTED SECTION.
@@ -1727,13 +1827,10 @@ CLASS zcl_some_class IMPLEMENTATION.
"----------------------------------------------------------------
"-------- Method chaining with a functional method call ---------
"----------------------------------------------------------------
"This example chained method call includes a chained attribute access
"at the end so that the target variable contains the content of the
"attribute.
"----------------------------------------------------------------
"Hallo NAME. This is an example of method chaining.
DATA(some_text) = NEW zcl_some_class(
DATA(text1) = NEW zcl_some_class(
)->add_text( `Hallo`
)->add_space(
)->add_text( xco_cp=>sy->user( )->name
@@ -1753,16 +1850,50 @@ CLASS zcl_some_class IMPLEMENTATION.
)->add_space(
)->add_text( `chaining`
)->add_period(
)->return_text( ).
out->write( text1 ).
"The following example chained method call includes a chained attribute
"access at the end so that the target variable contains the content of
"the attribute.
"Example result: Today is 2025-03-05. It's 14:30:38. Have a nice day.
DATA(text2) = NEW zcl_some_class(
)->add_text( `Today`
)->add_space(
)->add_text( `is`
)->add_space(
)->add_text( xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value
)->add_period(
)->add_space(
)->add_text( `It's`
)->add_space(
)->add_text( xco_cp=>sy->time( xco_cp_time=>time_zone->user
)->as( xco_cp_time=>format->iso_8601_extended
)->value
)->add_period(
)->add_space(
)->add_text( `Have`
)->add_space(
)->add_text( `a`
)->add_space(
)->add_text( `nice`
)->add_space(
)->add_text( `day`
)->add_period(
)->text.
out->write( some_text ).
out->write( text2 ).
"----------------------------------------------------------------
"-------- Method chaining with a standalone statement -----------
"----------------------------------------------------------------
"In the example, the final method call in the chain receives the
"classrun instance available in the implementation of the
"if_oo_adt_classrun~main method.
"In the example, the final method call in the chain receives
"the classrun instance available in the implementation of the
"if_oo_adt_classrun~main method. The method implementation
"includes the writing to the console.
"Console output: Lorem ipsum dolor sit amet
NEW zcl_some_class( )->add_text( `Lorem`
@@ -1797,6 +1928,10 @@ CLASS zcl_some_class IMPLEMENTATION.
ref = me.
ENDMETHOD.
METHOD return_text.
str = me->text.
ENDMETHOD.
ENDCLASS.
```
@@ -4284,6 +4419,130 @@ obj_factory = class=>factory_method( par = ... ).
<p align="right"><a href="#top">⬆️ back to top</a></p>
### ABAP Doc Comments
- The ABAP Doc documentation tool allows you to add special ABAP Doc comments to ABAP source code for documentation.
- ABAP Doc comments consist of one or more lines starting with `"!`.
- You can place these comments before declarations (e.g., in classes and methods) to document functionality, add notes, and so on.
- In ADT, click, for example, on class names or methods to display ABAP Doc comments (if available) in the *ABAP Element Info*, or choose F2 to display the information.
- Find more information on ABAP Doc [here](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENDOCCOMMENT.html).
- The following example demonstrates ABAP Doc comments, showing various commenting options, including:
- Using HTML tags for formatting. Only a selected set of HTML tags is supported. You can choose *CTRL + Space* in the ABAP Doc comment for input help.
- Special tagging and linking options. Refer to the [documentation](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/ABENDOCCOMMENT.html) for more details.
- Special method signature specifications like `@parameter | ...` for parameters and `@raising | ...` for declared exceptions.
```abap
"! <p class="shorttext">Demo ABAP Doc comments</p>
"!
"! <p>This class serves as an example to illustrate comments for ABAP Doc.
"! The comments begin with the string <strong>"!</strong>, a special form of regular comments introduced by <strong>"</strong>. <br/><br/>
"! The {@link zcl_some_class.METH:calculate} method of the example class performs a calculation. </p>
"! <h2>Notes</h2>
"! <ul>
"! <li>ABAP Doc documents declarations in ABAP programs.</li>
"! <li>The ABAP development tools for Eclipse (ADT) support ABAP Doc.</li>
"! <li>The content of ABAP Doc comments is converted to HTML and displayed appropriately.</li>
"! <li>Check out the supported HTML tags by choosing <em>CTRL + Space</em> after <em>"!</em>. h1 - h3 tags can also be used.</li>
"! <li>Escaping special characters: <strong>&quot;, &apos;, &lt;, &gt;, &#64;, &#123;, &#124;, and &#125;</strong></li>
"! </ul>
"! <h2>Steps</h2>
"! <ol>
"! <li>Create a demo class named <em>zcl_some_class</em></li>
"! <li>Copy and paste the code of this example and activate.</li>
"! <li>Click the class name to display the comments in the <em>ABAP Element Info</em> ADT tab.</li>
"! <li>You can also choose F2 for the class name to display the information.</li>
"! </ol>
"! <h3>More examples</h3>
"! Find more code examples in ABAP cheat sheet demo classes, such as {@link zcl_demo_abap_objects} and others. <br/>
"! <h3>Link examples</h3>
"! <ul>
"! <li>Repository objects such as the following, and more:
"! <ul><li>Classes, e.g. {@link zcl_some_class}</li>
"! <li>Interfaces, e.g. {@link if_oo_adt_classrun}</li>
"! <li>CDS artifacts, e.g. {@link i_apisforclouddevelopment}</li>
"! <li>DDIC database tables, e.g. {@link zdemo_abap_carr}</li>
"! <li>DDIC data elements, e.g. {@link land1}</li></ul>
"! <li>Method: {@link zcl_some_class.METH:calculate}</li>
"! <li>Constant: {@link zcl_some_class.DATA:const}</li>
"! <li>Data object: {@link zcl_some_class.DATA:dobj}</li>
"! <li>Method parameter: {@link zcl_some_class.METH:calculate.DATA:operator}</li>
"! <li>Interface implemented in a class: {@link zcl_some_class.INTF:if_oo_adt_classrun}</li>
"! <li>Interface method implemented in a class: {@link zcl_some_class.INTF:if_oo_adt_classrun.METH:main}</li>
"! <li>DDIC domain: {@link DOMA:land1}</li>
"! <li>XSLT: {@link XSLT:id}</li>
"! </ul>
CLASS zcl_some_class DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES: basetype TYPE c LENGTH 1,
BEGIN OF ENUM t_enum_calc STRUCTURE en_calc BASE TYPE basetype,
init VALUE IS INITIAL,
plus VALUE '+',
minus VALUE '-',
multiply VALUE '*',
divide VALUE '/',
END OF ENUM t_enum_calc STRUCTURE en_calc.
"! <p>This method performs a calculation.</p>
"! @parameter num1 | First number for the calcation
"! @parameter num2 | Second number for the calcation
"! @parameter operator | Operator. Only one of the four operators +, -, *, / is allowed.
"! The value is represented by an enumerated type. Note that there is no handling if
"! the assigned value is initial.
"! @parameter result | Result of the calculation
"! @raising cx_sy_zerodivide | Zero division
"! @raising cx_sy_arithmetic_overflow | Arithmetic overflow
CLASS-METHODS calculate IMPORTING num1 TYPE i
num2 TYPE i
operator TYPE t_enum_calc
RETURNING VALUE(result) TYPE decfloat34
RAISING cx_sy_zerodivide cx_sy_arithmetic_overflow.
"! This is an ABAP Doc comment for a constant
CONSTANTS const TYPE i VALUE 123.
"! This is an ABAP Doc comment for a static attribute of a class
CLASS-DATA dobj TYPE i.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(result_plus) = calculate( num1 = 1 num2 = 10 operator = en_calc-plus ).
DATA(result_minus) = calculate( num1 = 1 num2 = 10 operator = en_calc-minus ).
DATA(result_multiply) = calculate( num1 = 2 num2 = 5 operator = en_calc-multiply ).
DATA(result_divide) = calculate( num1 = 10 num2 = 5 operator = en_calc-divide ).
out->write( data = result_plus name = `result_plus` ).
out->write( data = result_minus name = `result_minus` ).
out->write( data = result_multiply name = `result_multiply` ).
out->write( data = result_divide name = `result_divide` ).
ENDMETHOD.
METHOD calculate.
result = SWITCH #( operator
WHEN en_calc-plus THEN num1 + num2
WHEN en_calc-minus THEN num1 - num2
WHEN en_calc-multiply THEN num1 * num2
WHEN en_calc-divide THEN num1 / num2
ELSE '0' ).
ENDMETHOD.
ENDCLASS.
```
<p align="right"><a href="#top">⬆️ back to top</a></p>
## More Information
You can check the subtopics of

View File

@@ -1026,6 +1026,9 @@ READ TABLE dref->* ASSIGNING FIELD-SYMBOL(<read>) WITH KEY ('CARRID') = 'AA'.
DATA(line) = CONV zdemo_abap_carr( dref->*[ ('CARRID') = 'AA' ] ).
dref->*[ ('CARRID') = 'AA' ] = VALUE zdemo_abap_carr( BASE dref->*[ ('CARRID') = 'AA' ] carrid = 'XY' ).
dref->*[ ('CARRID') = 'XY' ]-('CARRID') = 'ZZ'.
"Note: As the example uses a fully generic type, explicit or implicit index
"operations are not allowed.
"dref->*[ 1 ]-('CARRID') = 'ZZ'.
"Table functions
DATA(num_tab_lines) = lines( dref->* ).
@@ -1285,9 +1288,9 @@ ASSIGN ('ZDEMO_ABAP_OBJECTS_INTERFACE')=>('CONST_INTF') TO <fs>.
ASSIGN NEW zcl_demo_abap_objects( )->('PUBLIC_STRING') TO <fs>.
"ELSE UNASSIGN addition
"If ELSE UNASSIGN is specified in the context of dynamic assignments/accesses,
"no memory area is assigned to the field symbol. It is unassigned after
"the ASSIGN statement.
"If ELSE UNASSIGN is specified and assignment does not work in the context
"of dynamic assignments/accesses, no memory area is assigned to the field
"symbol. It is unassigned after the ASSIGN statement.
"Note: For the static variant of the ASSIGN statement, i.e. if the memory area
"to be assigned following the ASSIGN keyword is statically specified, the addition
"ELSE UNASSIGN is implicitly set and cannot be used explicitly.
@@ -1370,7 +1373,7 @@ ASSIGN dobj_c10 TO <casttype> CASTING TYPE HANDLE tdo_elem. "1234
"CREATE DATA dref TYPE ... TABLE OF (typename) ...
"CREATE DATA dref TYPE REF TO (typename).
"CREATE DATA dref TYPE LINE OF (typename).
"CREATE DATA dref LIKE struc-(dobjname).
"CREATE DATA dref LIKE struc-(compname).
"CREATE DATA dref TYPE (absolute_name).
"CREATE DATA dref TYPE HANDLE type_description_object.
@@ -1490,6 +1493,18 @@ CREATE OBJECT oref_dyn TYPE ('ZCL_DEMO_ABAP_OBJECTS').
DATA cl TYPE string VALUE `ZCL_DEMO_ABAP_OBJECTS`.
CREATE OBJECT oref_dyn TYPE (cl).
"Specifying a wrong/non-existent type name
TRY.
CREATE OBJECT oref_dyn TYPE ('THIS_CLASS_DOES_NOT_EXIST').
CATCH cx_sy_create_object_error.
ENDTRY.
"Using an absolute name for the dynamic type specification
"Getting the absolute name using RTTI
DATA(abs_name_cl) = cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_OBJECTS' )->absolute_name.
CREATE OBJECT oref_dyn TYPE (abs_name_cl).
CREATE OBJECT oref_dyn TYPE ('\CLASS=ZCL_DEMO_ABAP_OBJECTS').
"Note: If the class has an instance constructor specified with importing
"parameters, you can (or must in the case of non-optional parameters) pass
"actual parameters.
@@ -2288,16 +2303,24 @@ ENDCLASS.
<p align="right"><a href="#top">⬆️ back to top</a></p>
### Dynamic Invoke
The following code snippet shows dynamically specifying [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") calls. The snippet covers methods. Find an example of a dynamic function module call in the [Program Flow Logic](./13_Program_Flow_Logic.md#function-module-example) cheat sheet.
- The following code snippet shows dynamically specifying [procedures](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenprocedure_glosry.htm "Glossary Entry") calls.
- The snippet covers methods. Dynamic method calls require `CALL METHOD` statements.
- Find an example of a dynamic function module call in the [Program Flow Logic](./13_Program_Flow_Logic.md#function-module-example) cheat sheet.
Syntax patterns:
``` abap
"Note: Dynamic method calls require a CALL METHOD statement.
"The following examples assume that there are no mandatory
"parameters defined for the method.
"Possible for methods of the same class, works like me->(meth)
CALL METHOD (meth).
"Class specified statically
CALL METHOD class=>(meth).
"Object reference variable specified statically;
"also possible for interface reference variables
CALL METHOD oref->(meth).
@@ -2305,6 +2328,7 @@ CALL METHOD oref->(meth).
"The following statements are possible for all visible static methods
"Class dynamically specified
CALL METHOD (class)=>meth.
"Class and method dynamically specified
CALL METHOD (class)=>(meth).
@@ -2328,38 +2352,10 @@ CALL METHOD class=>(meth) PARAMETER-TABLE ptab.
" value -> pointer to appropriate actual parameter,
" is of type REF TO data
"The addition EXCEPTION-TABLE for exceptions is not dealt with here.
"Example that uses the PARAMETER-TABLE addition
"Creating an instance by specifying the type statically
"An example class of the cheat sheet repository is used.
DATA(oref1) = NEW zcl_demo_abap_objects( ).
"Calling an instance method
"The method multiplies an integer by 3.
"The calculation result is returned.
DATA(result) = oref1->triple( i_op = 2 ). "6
"Dynamic equivalent
"Creating an instance of a class by specifying the type
"dynamically
DATA oref2 TYPE REF TO object.
CREATE OBJECT oref2 TYPE ('ZCL_DEMO_ABAP_OBJECTS').
"Creating parameter table
DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'I_OP'
kind = cl_abap_objectdescr=>exporting
value = NEW i( 3 ) )
( name = 'R_TRIPLE'
kind = cl_abap_objectdescr=>returning
value = NEW i( ) ) ).
"Dynamic method call and specifying a parameter table
CALL METHOD oref2->('TRIPLE') PARAMETER-TABLE ptab.
result = ptab[ name = 'R_TRIPLE' ]-('VALUE')->*. "9
```
**Example Class**
The commented example class below explores dynamic method calls with a simple method. You can create a demo class called `zcl_some_class` and copy and paste the following code. Once activated, you can choose *F9* in ADT to run the class. The example is designed to display output in the console that shows the result of calling different methods.
**Example class 1**
The following example class explores dynamic method calls with simple methods. You can create a demo class called `zcl_some_class` and copy and paste the following code. Once activated, you can choose *F9* in ADT to run the class. The example is not designed to display output in the console.
```abap
CLASS zcl_some_class DEFINITION
@@ -2369,141 +2365,185 @@ CLASS zcl_some_class DEFINITION
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS meth IMPORTING num1 TYPE i
num2 TYPE i
EXPORTING add TYPE i
subtr TYPE i
CHANGING abs_val TYPE i
RETURNING VALUE(ret) TYPE string.
METHODS inst_meth1.
METHODS inst_meth2 IMPORTING text TYPE string
RETURNING VALUE(result) TYPE string.
CLASS-METHODS stat_meth1.
CLASS-METHODS stat_meth2 IMPORTING text TYPE string
EXPORTING result TYPE string.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_some_class IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"-------------------- Static method call --------------------
"The following examples use both named and unnamed data objects randomly,
"i.e. ...=>(meth_name) or ...=>(`SOME_METH`), for example.
DATA(cl_name) = `ZCL_SOME_CLASS`.
DATA(meth_name1) = `STAT_METH1`.
"Creating object reference
DATA(oref_stat) = NEW zcl_some_class( ).
DATA: calc_result_addition TYPE i,
calc_result_subtraction TYPE i,
some_number TYPE i VALUE -123.
"------------------------------------------------------------------------
"---------------- Calling static methods dynamically --------------------
"------------------------------------------------------------------------
DATA(result_stat) = oref_stat->meth( EXPORTING num1 = 7
num2 = 3
IMPORTING add = calc_result_addition
subtr = calc_result_subtraction
CHANGING abs_val = some_number ).
"-------- Method without mandatory parameters defined --------
"The syntax is possible for methods of the same class.
CALL METHOD (meth_name1).
out->write( data = calc_result_addition name = `calc_result_addition` ).
out->write( data = calc_result_subtraction name = `calc_result_subtraction` ).
out->write( data = some_number name = `some_number` ).
out->write( data = result_stat name = `result_stat` ).
out->write( repeat( val = `*` occ = 80 ) ).
"The previous example method call works like me->(meth).
CALL METHOD me->(meth_name1).
"-------------------- Dynamic method calls --------------------
"The following method calls explore possible dynamic equivalents
"of the previous static method call.
"-------- Class specified statically, method specified dynamically --------
CALL METHOD zcl_some_class=>(meth_name1).
"-------- Class specified dynamically, method specified statically --------
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth1.
"-------- Class and method specified dynamically --------
CALL METHOD (`ZCL_SOME_CLASS`)=>(`STAT_METH1`).
"-------- Specifying non-optional parameters --------
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = `hallo`.
"Specifying the output parameter is optional
DATA res TYPE string.
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = `hallo` IMPORTING result = res.
ASSERT res = `HALLO`.
"-------- Some examples for handling errors when calling methods wrongly --------
"Instance method called using =>
TRY.
CALL METHOD zcl_some_class=>(`INST_METH1`).
CATCH cx_sy_dyn_call_illegal_method.
ENDTRY.
"The example method does not specify non-optional parameters.
TRY.
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2.
CATCH cx_sy_dyn_call_param_missing.
ENDTRY.
"Specifying a wrong parameter name
TRY.
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING hallo = `hallo`.
CATCH cx_sy_dyn_call_param_missing.
ENDTRY.
"Assigning wrong, non-compatible type
TRY.
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = VALUE string_table( ( `hi` ) ).
CATCH cx_sy_dyn_call_illegal_type.
ENDTRY.
"Specifying wrong parameter kinds (the example method specifies importing
"and exporting parameters, and not a returning parameter)
TRY.
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 EXPORTING text = `hallo` RECEIVING result = res.
CATCH cx_sy_dyn_call_illegal_type.
ENDTRY.
"------------------------------------------------------------------------
"---------------- Calling instance methods dynamically ------------------
"------------------------------------------------------------------------
"Creating an instance of a class by specifying the type dynamically
DATA oref TYPE REF TO object.
CREATE OBJECT oref TYPE ('ZCL_SOME_CLASS').
some_number = -99.
"Specifying parameters statically
DATA result_dyn TYPE string.
CALL METHOD oref->('METH')
EXPORTING
num1 = 10
num2 = 4
IMPORTING
add = calc_result_addition
subtr = calc_result_subtraction
CHANGING
abs_val = some_number
RECEIVING
ret = result_dyn.
"--- Object reference variable specified statically, method specified dynamically ---
"Note: This is a also possible for interface reference variables.
CALL METHOD oref->(`INST_METH1`).
out->write( data = calc_result_addition name = `calc_result_addition` ).
out->write( data = calc_result_subtraction name = `calc_result_subtraction` ).
out->write( data = some_number name = `some_number` ).
out->write( data = result_dyn name = `result_dyn` ).
out->write( repeat( val = `*` occ = 80 ) ).
"-------- Specifying non-optional parameters --------
CALL METHOD oref->(`INST_METH2`) EXPORTING text = `abap`.
"The following examples show erroneous dynamic method calls
"Missing parameters
TRY.
CALL METHOD oref->('METH').
CATCH cx_root INTO DATA(error).
DATA(cx_class) = cl_abap_typedescr=>describe_by_object_ref( error )->get_relative_name( ).
out->write( |{ cx_class } raised: { error->get_text( ) }| ).
out->write( repeat( val = `*` occ = 80 ) ).
ENDTRY.
CALL METHOD oref->(`INST_METH2`) EXPORTING text = `abap` RECEIVING result = res.
ASSERT res = `ABAP`.
"Illegal type of an actual parameter
TRY.
CALL METHOD oref->('METH')
EXPORTING
num1 = 'nope'
num2 = 1
IMPORTING
add = calc_result_addition
subtr = calc_result_subtraction
CHANGING
abs_val = some_number
RECEIVING
ret = result_dyn.
CATCH cx_root INTO error.
cx_class = cl_abap_typedescr=>describe_by_object_ref( error )->get_relative_name( ).
out->write( |{ cx_class } raised: { error->get_text( ) }| ).
out->write( repeat( val = `*` occ = 80 ) ).
ENDTRY.
"Note that calling static methods using object reference variables is also possible.
CALL METHOD oref->(`STAT_METH1`).
"Dynamic method call using a parameter table
DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'NUM1'
CALL METHOD oref->(`STAT_METH2`) EXPORTING text = `test` IMPORTING result = res.
ASSERT res = `TEST`.
"------------------------------------------------------------------------
"------------------- PARAMETER-TABLE addition ---------------------------
"------------------------------------------------------------------------
"------- Static equivalents to the dynamic statement below -------
DATA(oref_stat) = NEW zcl_some_class( ).
res = oref_stat->inst_meth2( `abc` ).
ASSERT res = `ABC`.
"For demo purposes, including chained method call options:
"Functional method call
res = NEW zcl_some_class( )->inst_meth2( `def` ).
ASSERT res = `DEF`.
"Standalone statement)
NEW zcl_some_class( )->inst_meth2( EXPORTING text = `ghi` RECEIVING result = res ).
ASSERT res = `GHI`.
"------- Dynamic CALL METHOD statements using the PARAMETER-TABLE addition -------
"Creating parameter table for an instance example method
DATA(ptab) = VALUE abap_parmbind_tab( ( name = 'TEXT'
kind = cl_abap_objectdescr=>exporting
value = NEW i( 2 ) )
( name = 'NUM2'
kind = cl_abap_objectdescr=>exporting
value = NEW i( 10 ) )
( name = 'ADD'
kind = cl_abap_objectdescr=>importing
value = NEW i( ) )
( name = 'SUBTR'
kind = cl_abap_objectdescr=>importing
value = NEW i( ) )
( name = 'ABS_VAL'
kind = cl_abap_objectdescr=>changing
value = NEW i( -987 ) )
( name = 'RET'
value = NEW string( `jkl` ) )
( name = 'RESULT'
kind = cl_abap_objectdescr=>returning
value = NEW string( ) ) ).
value = NEW string( ) )
).
CALL METHOD oref->('METH') PARAMETER-TABLE ptab.
CALL METHOD oref->(`INST_METH2`) PARAMETER-TABLE ptab.
"Excursion: Accessing structure components dynamically
res = ptab[ name = 'RESULT' ]-('VALUE')->*.
ASSERT res = `JKL`.
"Creating parameter table for a static example method
ptab = VALUE abap_parmbind_tab( ( name = 'TEXT'
kind = cl_abap_objectdescr=>exporting
value = NEW string( `mno` ) )
( name = 'RESULT'
kind = cl_abap_objectdescr=>importing
value = NEW string( ) ) ).
"Demonstrating static/dynamic specification variants
CALL METHOD (`ZCL_SOME_CLASS`)=>(`STAT_METH2`) PARAMETER-TABLE ptab.
res = ptab[ name = 'RESULT' ]-('VALUE')->*.
ASSERT res = `MNO`.
CALL METHOD zcl_some_class=>(`STAT_METH2`) PARAMETER-TABLE ptab.
res = ptab[ name = 'RESULT' ]-('VALUE')->*.
ASSERT res = `MNO`.
CALL METHOD (`ZCL_SOME_CLASS`)=>stat_meth2 PARAMETER-TABLE ptab.
res = ptab[ name = 'RESULT' ]-('VALUE')->*.
ASSERT res = `MNO`.
out->write( ptab ).
ENDMETHOD.
METHOD meth.
add = num1 + num2.
subtr = num1 - num2.
DATA(abs_val_copy) = abs_val.
"Getting the absolute value
abs_val = abs( abs_val ).
ret = |Values of importing parameters: num1 = { num1 STYLE = SIMPLE }| &&
|, num2 = { num2 STYLE = SIMPLE }\nValues of exporting parameters: | &&
|add = { add STYLE = SIMPLE }, subtr = { subtr STYLE = SIMPLE }| &&
|\nChanging parameter: abs_val (original) = { abs_val_copy STYLE = SIMPLE }, | &&
|abs_val (modified) = { abs_val STYLE = SIMPLE }|.
METHOD inst_meth1.
...
ENDMETHOD.
METHOD inst_meth2.
result = to_upper( text ).
ENDMETHOD.
METHOD stat_meth1.
...
ENDMETHOD.
METHOD stat_meth2.
result = to_upper( text ).
ENDMETHOD.
ENDCLASS.
```
**Excursion**
**Example class 2**
The following simplified example highlights several things in the context of a dynamic invoke example:
- Dynamic invoke and assigning actual parameters to formal parameters statically