The first chapter introduced you to the basic concepts of object-oriented ABAP. In this chapter, we continue moving ahead and cover a number of useful topics that you need to know to work with ABAP Objects.
We also cover the concepts of local and global classes along with demos and examples. We will move one more step forward. I will use the global as well as local classes to exemplify my point.
CASE TYPE OF used for determining the type of an object reference variable
The NEW operator
Defining types in classes
Inline declaration
Specifying constant values within classes
Static constructor concept
Method chaining and functional methods
Event handling
Finding the Type of an Object Reference Variable: Revisited
Depending on the requirements, it may be necessary to confirm if an object belongs to a particular class, i.e, for example, if an EMPLOYEE object is an instance of the ZCL_TEST_EMPLOYEE class.
As mentioned in last chapter, since NetWeaver 7.50, we have a new expression called IS INSTANCE OF that can be used in conjunction with the IF statement to confirm if a particular object belongs to a particular class. The usage is very simple, just like any other expression within an IF statement.
Here, we defined a variable called EMPLOYEE that is a reference to the ZCL_TEST_EMPLOYEE class. We then used the CREATE OBJECT statement to instantiate the given object with suitable attribute values for number, name, and country.
There is another way we can determine the type of the given employee.
Here, note that the TYPE OF addition has been used along with CASE, and the TYPE variant is written with the WHEN clause. This code also checks whether the employee object is an instance of the ZCL_TEST_EMPLOYEE class. The code output is the same as shown in Figure 2-1.
Using the New Operator to Create an Object
Starting with NetWeaver 7.4, ABAP allows creation of objects via the NEW operator. This operator provides an alternate to the CREATE OBJECT statement. There are a number of ways in which it may be used for objects’ instantiation. The NEW operator may be used for creating instances of both local and global classes.
- 1.Used in conjunction with the class name. The construct for this is shown here:DATA MYOBJ TYPE REF TO MYCLASS.MYOBJ = NEW myclass(param1 = val1param2 = val2paramN = valN).Using the inline declaration supported by ABAP 7.40, the same form may be written in one single statement:DATA(MYOBJ) = NEW myclass(param1 = val1param2 = val2...paramN = valN).
In both of the previous cases, the NEW operator is used in conjunction with the class name. This will create an instance of the MYCLASS class and assign to the reference variable MYOBJ. In the latter case, there is an implicit declaration of MYOBJ based on the MYCLASS class (where the type of MYOBJ is derived from the content of the right side of the assignment). If the constructor of the class has mandatory importing parameters, the corresponding data must be passed to the instance constructor within the parentheses, as shown.
- 2.Used with the # character. Another form of the NEW operator is using it with the # character. The syntax is as follows:DATAMYOBJ TYPE REF TO MYCLASS.MYOBJ = NEW #( param1 = val1param2 = val2...paramN = valN).
We declare a variable called MYOBJ referred to the MYCLASS class. Since we already declared a reference variable based on the class in question, there is no need to specify the class again with the NEW operator. Instead of the class name, the # character can be used. Any non-optional parameters are provided in parentheses, as shown earlier.
To better understand how to use the two forms of the NEW operator, let’s look at a few examples. In this example, we use the global football player class ZST6_FOOTBALL_PLAYER_CLASS that we defined earlier in the book.
We created an object of the global class using the CREATE OBJECT statement. The DISPLAY_PLAYER_DETAILS method was then called to print the details of the created football player. This block of code was earlier used to create a football player object.
We used the inline declaration of FOOTBALL_PLAYER along with the NEW operator in a single statement. This involves the implicit definition of FOOTBALL_PLAYER as a reference of class ZST6_FOOTBALL_PLAYER_CLASS. In this case, we did not have to declare a variable based on the class in a separate statement. An object for the given class is created and the reference variable FOOTBALL_PLAYER may then be used to display the player details.
In this usage form, we declare a reference variable FOOTBALL_PLAYER for the class ZST6_FOOTBALL_PLAYER_CLASS. We use the NEW operator to create an object of the given class. Instead of specifying the name of the class, we use the # character. The reference to the newly created object is assigned to the FOOTBALL_PLAYER variable. The values for the various importing parameters are supplied as shown earlier. The complete class name is not required, as the system automatically detects it from the type of the variable to which the created object’s reference is assigned (in our case, FOOTBALL_PLAYER).
Defining Our Own Types in Classes
In this section, we learn how to define our own types in local and global classes. You may define types within the class in the private or the public sections (as well as the protected section). We will first see how to define types in local classes.
Here we defined our own type based on the public section.
You may define your own variables within the class and outside using the data statement.
As mentioned earlier, it is also possible to define a type in a global class. To define a type in an SE24 transaction, a few additional steps are required.
Save and activate the class.
Constants in Classes
Just like we have constants while making report programs, we can declare constants within local and global classes. Within the realm of classes, constants are special static attributes within a class. Constants may be public or private attributes and may not be changed within the class or outside the class.
Here we have the MYCLASS class, and within the public section, we defined a constant by the name MYCONSTANT and assigned it the value XYZ. Since this is a public attribute, it can be accessed outside the class using the => operator. The value is assigned to the string called myvalue. The contents of myvalue are printed.
You may not be able to access myconstant outside the class, like all other private attributes.
It is also possible to define constants within global classes. Let’s see how this is done using the Class Builder. Suppose we have a class called ZCL_TEST_EMPLOYEE (see Figure 2-6).
Dictionary Types for Global Classes
In Chapter 1, we saw how to define a type pertaining to an internal table comprised of employee objects. Earlier we did this by defining a table type local to a program. It is also possible to define a table type globally in the transaction SE24 Class Builder. This may later be used in any program to create objects based on the underlying class. In this section, we see how this is done.
- 1.Go to transaction SE11. This will display the screen shown in Figure 2-7.
- 2.Enter the name of the table type that you want to create in the Data Type field and click the Create button. (As you will see, we called our type ZEMP_OBJECT_TABLE_TYPE.) This will display a small dialog box, as shown in Figure 2-8.
- 3.
Choose the Table Type option and press Enter. This will take you to the screen shown in Figure 2-9.
- 4.Choose the Reference type option.
- 5.
Enter the name and description in the fields provided. Choose the Reference Type option and enter the name of the employee class (i.e., ZCL_TEST_EMPLOYEE) in the field as shown. Once you are done, save and activate the type using the CTRL+F3 keys.
Static Constructor
In Chapter 1, we discussed instance constructors and saw related coding examples. It is also possible to define static constructors within classes.
A static constructor is also known as a class constructor . As with the other static methods, the static constructor is only able to address the static components residing within the class in question.
We also have a static constructor in a class. This is called ONLY once for a class (and internal session), prior to the first access made to the class.
As you will see, we declared a static constructor by the name class_constructor of the class in question. This statement may only be written within the public section of the class (declaration). By default, every class has a built-in class_constructor method in the public section.
However, without the declaration, this constructor is blank.
In contrast to the instance constructor, the static constructor is executed once for each class within an internal session. This execution occurs before the first access to the class in question, such as an instance creation.
You can access any static component of the class using =>. It is also possible to call a static method within the static constructor.
Any failed attempt to dynamically address a nonexistent component of a class does not result in the static constructor being called.
Here we have a local class called MY_CLASS that has two static methods, namely CLASS_CONSTRUCTOR and MY_STATIC_METHOD. Within the two methods, there are specific messages outputted in order to show the sequence of method execution. We call the static method only using the component class selector =.>.
Calling the static method MY_STATIC_METHOD will result in the static constructor being executed prior to MY_STATIC_METHOD.
Now let’s look at the same requirement fulfilled using a global class. We assume for this example that a class already exists by the name ZCL_TEST_EMPLOYEE.
- 1.
Open the class in edit mode. Then click the Methods tab.
- 2.Under the method list, enter the name CLASS_CONSTRUCTOR and press Enter. This will automatically populate Static Method into the Level field, as shown in Figure 2-11.
As you will see, the Level is set to Static Method and cannot be changed. In addition, the visibility column will be automatically populated with Public. It is worth noting that if any other visibility, such as Private, is entered in the column, upon pressing Enter, the Visibility will change back to Public.
Method Revisited
In Chapter 1, we saw local as well as global methods. In this section, we will go a few steps further with methods. We will see how to specify internal tables as method parameters, method chaining, and functional methods.
Specifying Internal Tables as Method Parameters
So far we have only seen integers and strings as types of method parameters. It is also possible to specify internal tables as exporting, importing, and returning parameters of class methods.
Let’s now complicate things a bit. In this section, we see how we can specify an internal table as a parameter of the method of a class. In the football player example introduced in Chapter 1, we define a new method, called RETURN_LIST_OF_PLAYERS. Instead of writing the attributes of each player object on the screen, we will return the list of player objects in an internal table.
As you will see, we have specified an exporting parameter called PLAYERS_TAB based on the TY_PLAYER_TAB type. It must be noted that the table type must be specified here. (This is a TYPE STANDARD TABLE type based on TY_PLAYER.)
The internal table is then returned as an exporting parameter.
This method is called after instantiation of two player objects, as shown in our previous example, which shows the contents of our players_tab. We use inline declaration to return this in players_tab.
Inline Declarations While Calling Methods
Since 740, ABAP supports inline declaration of variables. This holds true for method calls as well. We will see how to call methods and specify (as parameters) variables that were not declared earlier in the program.
Consider a situation where we have an employee class called ZCL_EMPLOYEE that has a method called GET_NAME_AND_COUNTRY that returns the name and country of the employee in question.
This is the traditional method, where we first declare variables pertaining to the importing parameters of the method. The value of name and country is then returned in the declared variables.
As you will see, we have not done any prior declaration of the two variables NAME and COUNTRY. Rather we used the feature of inline declaration while specifying the parameters of the method in question. The variable name to be declared inline must be in parentheses and must be preceded by data. The output of this piece of code and the one shown earlier are exactly the same.
Using inline declarations is not just restricted to exporting parameters of the method. They may also be used for RECEIVING parameters (we will discuss this in an upcoming section).
Functional Methods
So far, we have only seen methods that take as input a number of importing parameters and then export a number of parameters (exporting parameters). We also have a special type of method that returns a single result or returning value. Such methods are known as functional methods. These may be defined in local and global classes. It is also possible to have a functional method as a static method or an instance method within a class.
As you can see, the static method CALC_AVERAGE takes as input two integer values int1 and int2 and returns a single parameter called AVERAGE as the returning parameter. The example shows a local class, called func_method_class. As with other methods, the code of this is written in the IMPLEMENTATION of the class.
Here we used the assignment operator to return the average result in the variable AV. When using a functional method, you do not have to specify the parameter names for the return value explicitly in the parameter list, as shown in the code.
When you are done, save and activate the class. The method created here may be called in programs the same way the local functional method was called.
Here we have a method called PRIMARY_RECORD_REF that does not have a returning parameter. But we have used this improperly, which results in a syntax error.
This error occurs for global as well as local classes. Starting from NetWeaver 7.50, it is also possible to specify exporting parameters for functional methods.
Specifying Exporting and Returning Parameters for Functional Methods
The newer NetWeaver release provides an interesting feature of functional methods. In addition to a returning parameter, a functional method can also have an exporting parameter. However, note that functional methods support only one returning parameter and any number of other formal parameters, including importing and exporting. We can create local or global functional methods, which may be static or instance methods.
In the examples, we cover both scenarios of defining functional methods locally and globally that have both exporting and returning parameters. We use static method in these examples for better understanding.
As you see in the code, we defined a class locally within the program. The class name is newclass. A static method, func_av_and_total, is defined within the class, which calculates both the average and the sum of the two numbers supplied to the method.
This method has two import parameters (myint1 and myint2) of type Integer. The sum is the exporting parameter, whereas AV is the returning parameter of the type myty_dec2. (This is a user-defined type defined within the class.)
In the class implementation, we specified how the sum and the average are calculated. We add the two numbers to get sum and divide the total by 2 in order to get the average that is returned in parameter AV.
In the example, a static method is called without creating a class instance. The variable AV is defined using an inline declaration. The method returns the average of the input parameters, which is captured in the variable AV. This may later be printed on the user screen.
In this class definition, SUM is defined as an exporting parameter and AV is defined as a returning parameter. The ty_dec2 type is defined using the Types tab.
Methods Calling Other Methods
A declared method can call other methods in the source code. For example, it is possible for a local class method to call a (public) method of another local class, or a static local method can call a static global or local method. At the time of calling, the control switches just like other modularization units, such as form subroutine and function modules, and returns to the calling method.
Method Chaining
A newer concept that has evolved is method chaining. This involves combining calls of functional methods (i.e., methods that have one returning value as output). The chaining of methods makes the code more compact and allows you to fulfill requirements without the need for additional reference variables. There are two types of chaining possible: chained method access and chained method call. (The primary emphasis of this section is on chained method access.) Let’s take a look at what each of these means.
The return value of one functional method is a reference to an object that is used to call the next method in the chain. The returning value of the last method is used as an operand.
In this case, the first use may be a class component selector (=>) or an object component selector (->). After that, all the methods are called using the component. Or, in other words, the first method may be a static or an instance method. Other than that, you must have all functional instance methods.
The return value of the last method (INST_METH_B) must refer to the object that contains the INST_ATTR attribute. In this case, the return values of the previous functional methods are variables that refer to objects for the next method.
There is also no need to define the FUNCTIONS variable, and the coding is very compact.
Event Handling in ABAP Objects
The topic of ABAP Objects is incomplete without one important component that may be included within a class definition—events.
Events are signals generated by a class or its object. They may be the result of changes in the state of an object, such as Employee Hired, Employee Changed, or Player Created.
Just like any other components of a class, there may be static or instance events. Static events are independent of any particular object of a class. Static events may be triggered from both static and instance methods, whereas instance events may be triggered from instance methods only.
- Defining the method as an instance or static event within the respective class definition. The class containing the event may be a subclass of another class, or may have a number of subclasses derived from it. You may also define an event in an interface. (The event will then be part of the class(es) that implement(s) the interface.) To define the event as static, use this code:CLASS_EVENTS <event_name>.On the other hand, the following statement defines an instance event:EVENTS <event_name>.
Raising the event at a suitable place using the RAISE EVENT statement.
The parameters are specified after the EXPORTING ADDITION. For an instance event, an implicit parameter called SENDER is applicable. This parameter holds a reference to the object for which the event has been generated. For example, when the instance event called PLAYER_CREATED is raised, SENDER will contain the reference to the player object in question. For static events, the SENDER parameter is not there.
Defining and implementing the event handler method. This may be defined in the same class or in a separate class. Within the handler class implementation, you write the method code to be executed upon event trigger. The parameters available to the method (i.e., the ones exported via the RAISE statement) may be used by the developer for fulfilling user requirements.
- Registering the method to react to events. The SET HANDLER statement is used for this purpose. If the event is static, the syntax may be of the form shown here:SET HANDLER <method_name>.
In the case of an instance event, the SET HANDLER statement will contain the additions FOR ALL INSTANCES or FOR (referring to a specific object for whose event the event handler is to be executed). It is possible to specify all instances or a particular object instance whose raised event is to be caught and the handler method is executed.
This is an important step that defines the link between the handler method and the event that is to be raised. If the registration is not performed, the handler method will not be executed even if the event gets triggered successfully with all essential information passed.
In the next section, we see these steps in detail as applied to our football player example.
A Working Example
In this section, we look at a full-fledged working example of event handling. For the sake of our example, we see how events may be defined and handled in local classes.
Triggering and Handling the PLAYER_CREATED Event
We add the event triggering functionality for our local football player class defined earlier. We create a separate event handler class for handling our PLAYER_CREATED event .
- 1.As mentioned, we need to define the event for our football player class. In our case, we name the event PLAYER_CREATED. This is defined as an instance event, as shown here:events : player_created .
- 2.We make sure that the event is defined in the public section of the class. We then raise the event. This is done using the RAISE EVENT statement as shown here:raise event player_created.
- 3.We put this in the constructor, as shown here:method constructor.call method super->constructorexportingname = nameweight = weightheight = height.me->football_club = football_club.raise event player_created."" nothing exported"" but created object passed"" via implicit SENDER parameterendmethod .
- 4.
We will not pass a parameter explicitly to the RAISE event. Next we create an event handler class with the name MYHANDLERCLASS. Within the class, there is a handler method called MYHANDLER defined as a static class method. Within the definition of the class for our handler method, we specify that it is for the PLAYER_CREATED event of the football player class.
Note that the importing implicit parameter SENDER is also specified. The sender contains a reference to the object for which the event has been triggered.
Within the method code, we will simply call the DISPLAY_PLAYER_DETAILS method of the football player class. This will display the various attributes of the newly created football player.
In this example, we have seen a football player class inherited from a player class. The inheritance concept will be explained in detail in the next chapter.
The name of the method along with class name is specified. Since the MYHANDLER is a static method, we use the class component selector (=>). We use the FOR ALL INSTANCES addition in order for the handler method to be executed for all instances of the FOOTBALL_PLAYER class.
When the program is executed, the CREATE OBJECT statement for the football player is executed. Whenever a new football player is created, a Player_Created event is triggered. This is an instance event raised via a RAISE EVENT statement in the constructor of the FOOTBALL_PLAYER class. Since we have registered the MYHANDLER method for the PLAYER_CREATED event of all instances of the football player class, the handler method gets executed. The method receives SENDER as an importing parameter, which is the reference to the football player object for which the event is raised. Within the handler method, we call the DISPLAY_PLAYER_DETAILS method of the FOOTBALL_PLAYER class to display the details of the football player object that is created.
Summary
In this chapter, we covered a number of useful topics that you need to know in order to work with ABAP Objects. We discussed the CASE TYPE OF construct used for determining the type of an object reference variable followed by a discussed of the “new” NEW operator.
We also saw how to apply inline declaration in ABAP Objects, constant declaration, method chaining, and functional methods. Finally, we saw a fully working demo of event handling.