-
Notifications
You must be signed in to change notification settings - Fork 286
/
zcl_demo_abap_oo_inheritance_1.clas.abap
219 lines (182 loc) · 9.73 KB
/
zcl_demo_abap_oo_inheritance_1.clas.abap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
"! <p class="shorttext"><strong>ABAP object orientation - Inheritance</strong><br/>ABAP cheat sheet example class</p>
"!
"! <p>The example class explores inheritance and demonstrate a selection of the inheritance-related syntax.
"! The inheritance tree consists of four example classes. The base class {@link zcl_demo_abap_oo_inheritance_1}
"! includes the implementation of the classrun interface. Choose F9 in ADT to run the class.</p>
"! <p>Classes of the inheritance tree:</p>
"! <ul><li>{@link zcl_demo_abap_oo_inheritance_1}</li>
"! <li>{@link zcl_demo_abap_oo_inheritance_2}</li>
"! <li>{@link zcl_demo_abap_oo_inheritance_3}</li>
"! <li>{@link zcl_demo_abap_oo_inheritance_4}</li>
"! </ul>
"!
"! <h2>Purpose</h2>
"! <p>The purpose of the example and information output is to visualize and explore concepts and syntax related to
"! inheritance, checking out when and how methods are called, redefining methods, abstract and final classes and methods.</p>
"!
"! <h2>General notes on the example</h2>
"! <p>Many instance methods are declared in all classes to demonstrate inheritance. However, there is no meaningful implementation
"! in these methods in all classes. All instance methods include the same code. The purpose of the code in the method implementations
"! is to add a line to a log table (which is output to the console) with various pieces of information:</p>
"! <ul><li>Name of the method that is called</li>
"! <li>In which class the method is implemented when it is called</li>
"! <li>From which class the method is called</li>
"! <li>Whether the method is inherited, redefined, final, or a static method</li>
"! <li>Visibility of the method</li>
"! <li>Visibility of the method</li></ul>
"! <p>The information retrieval is implemented in a static method in the {@link zcl_demo_abap_oo_inheritance_1} class by getting callstack
"! information to determine which method in which class was called by whom. Based on the retrieved class and method names, RTTI
"! is used to get detailed information about the methods.</p>
"!
"! <h2>Notes on this class</h2>
"! <ul><li>Allows inheritance and represents the root class of the inheritance hierarchy</li>
"! <li>Declares several instance methods in each visibility section</li>
"! <li>One of them is declared with FINAL, so no redefinition is possible in subclasses.</li>
"! <li>Includes the implementation of the classrun interface meaning this class is executable using F9 in ADT.</li>
"! <li>The class includes an internal table that represents a log table and that is output to the console as described above.</li></ul>
"!
"! <h2>More information</h2>
"! <p>Find information on <strong>getting started with the example class</strong> and the
"! <strong>disclaimer</strong> in the ABAP Doc comment of class {@link zcl_demo_abap_aux}.</p>
CLASS zcl_demo_abap_oo_inheritance_1 DEFINITION
PUBLIC
CREATE PUBLIC .
PUBLIC SECTION.
"Classrun interface
INTERFACES if_oo_adt_classrun.
"Instance/static constructor declarations
METHODS constructor.
CLASS-METHODS class_constructor.
"Instance method declarations
METHODS meth_public_1.
"Final method
METHODS meth_public_1_final FINAL.
"Components used for logging information about method calls
TYPES: BEGIN OF s_log,
method TYPE string,
implemented_where TYPE string,
called_from TYPE syrepid,
is_inherited TYPE abap_boolean,
is_redefined TYPE abap_boolean,
is_final TYPE abap_boolean,
visibility TYPE abap_visibility,
is_static_method TYPE abap_boolean,
called_at TYPE utclong,
END OF s_log,
t_log TYPE TABLE OF s_log WITH EMPTY KEY.
CLASS-DATA log_tab TYPE t_log.
CLASS-METHODS get_method_info RETURNING VALUE(info) TYPE s_log.
PROTECTED SECTION.
METHODS meth_protected_1.
PRIVATE SECTION.
METHODS meth_private_1.
ENDCLASS.
CLASS zcl_demo_abap_oo_inheritance_1 IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
out->write( |ABAP cheat sheet example: ABAP Object Orientation - Inheritance\n\n| ).
"----- First level in the inheritance hierarchy ----
"Creating an instance of the class
DATA(oref_super) = NEW zcl_demo_abap_oo_inheritance_1( ).
"Calling methods of the class
oref_super->meth_public_1( ).
oref_super->meth_public_1_final( ).
oref_super->meth_protected_1( ).
oref_super->meth_private_1( ).
"----- Second level in the inheritance hierarchy ----
"The instance creation and method calling is delegated to
"a static method in the class
zcl_demo_abap_oo_inheritance_2=>perform_meth_calls_2( ).
"----- Third level in the inheritance hierarchy ----
"Note: The class zcl_demo_abap_oo_inheritance_3 is abstract and contains
"both non-abstract and abstract instance methods. Instances of abstract
"classes cannot be created. So, the following statement is not possible.
"DATA(oref_3) = NEW zcl_demo_abap_oo_inheritance_3( ).
"Instance components of an abstract class can be accessed via its subclasses.
"zcl_demo_abap_oo_inheritance_4 inherits from zcl_demo_abap_oo_inheritance_3 and
"redefines methods of zcl_demo_abap_oo_inheritance_3. Both abstract methods (which
"are mandatory to implement) and non-abstract methods are redefined. To also access
"the method implementations of the non-abstract instance methods of
"zcl_demo_abap_oo_inheritance_3, the respective implementations of the redefined
"methods in zcl_demo_abap_oo_inheritance_4 include method calls to the direct
"superclass using the syntax super->meth( ).. The instance methods of
"zcl_demo_abap_oo_inheritance_3 are called in the context of the static method call
"via zcl_demo_abap_oo_inheritance_4 below.
"----- Fourth level in the inheritance hierarchy ----
"As above, the instance creation and method calling is delegated to
"a static method in the class. This method call includes method calls to
"non-abstract instance methods implemented in zcl_demo_abap_oo_inheritance_3.
zcl_demo_abap_oo_inheritance_4=>perform_meth_calls_4( ).
"Writing the log table to the console
out->write( data = log_tab name = `log_tab` ).
"Excursion: Using RTTI to retrieve the name of the superclass
"As this class starts an inheritance hierarchy, the superclass of this class
"is the root class OBJECT.
DATA(tdo_cl) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_OO_INHERITANCE_1' ) ).
DATA(superclass) = tdo_cl->get_super_class_type( )->get_relative_name( ).
out->write( |\n\n| ).
out->write( data = superclass name = `superclass` ).
ENDMETHOD.
METHOD class_constructor.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD constructor.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_private_1.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_1.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_1.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_1_final.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD get_method_info.
"This method retrieves callstack information to determine which method in which
"class was called by whom.
"Based on the retrieved class and method names, RTTI is used to get detailed
"information about methods (such as the visibility or whether the method is
"inherited, redefined, final, and a static method).
"Getting callstack information
DATA(call_stack_tab) = xco_cp=>current->call_stack->full( )->from->position( 2
)->to->position( 2 )->as_text( xco_cp_call_stack=>format->adt( )
)->get_lines( )->value.
IF lines( call_stack_tab ) < 2.
RETURN.
ENDIF.
LOOP AT call_stack_tab INTO DATA(wa) TO 2.
DATA(tabix) = sy-tabix.
SPLIT wa AT ` ` INTO TABLE DATA(entry).
DELETE entry WHERE table_line IS INITIAL.
DATA(class_name) = condense( val = entry[ 1 ] to = `` ).
IF tabix = 1.
info-implemented_where = class_name.
DATA(meth_name) = condense( val = to_upper( entry[ 2 ] ) to = `` ).
info-method = meth_name.
IF class_name IS NOT INITIAL AND meth_name IS NOT INITIAL.
DATA(tdo_cl) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( class_name ) ).
DATA(methods_cl) = tdo_cl->methods.
DATA(meth_info) = VALUE #( methods_cl[ name = meth_name ] OPTIONAL ).
IF meth_info IS NOT INITIAL.
info-is_inherited = meth_info-is_inherited.
info-is_redefined = meth_info-is_redefined.
info-is_final = meth_info-is_final.
info-visibility = meth_info-visibility.
info-is_static_method = meth_info-is_class.
ENDIF.
ENDIF.
ELSE.
info-called_from = class_name.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.