0% found this document useful (0 votes)
12 views374 pages

S4D400 - Basic ABAP Programming

The document is a participant handbook for an instructor-led training course on Basic ABAP Programming, version 24. It outlines the course structure, including various units and lessons covering topics such as preparing the development environment, basic techniques, local classes, data modeling, and RESTful application programming. The target audience includes development consultants and developers looking to enhance their ABAP skills.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views374 pages

S4D400 - Basic ABAP Programming

The document is a participant handbook for an instructor-led training course on Basic ABAP Programming, version 24. It outlines the course structure, including various units and lessons covering topics such as preparing the development environment, basic techniques, local classes, data modeling, and RESTful application programming. The target audience includes development consultants and developers looking to enhance their ABAP skills.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 374

S4D400

Basic ABAP Programming

.
.
PARTICIPANT HANDBOOK
INSTRUCTOR-LED TRAINING
.
Course Version: 24
Course Duration:
SAP Copyrights, Trademarks and
Disclaimers

© 2023 SAP SE or an SAP affiliate company. All rights reserved.

No part of this publication may be reproduced or transmitted in any form or for any purpose without the
express permission of SAP SE or an SAP affiliate company.
SAP and other SAP products and services mentioned herein as well as their respective logos are
trademarks or registered trademarks of SAP SE (or an SAP affiliate company) in Germany and other
countries. Please see https://www.sap.com/corporate/en/legal/copyright.html for additional
trademark information and notices.
Some software products marketed by SAP SE and its distributors contain proprietary software
components of other software vendors.
National product specifications may vary.
These materials may have been machine translated and may contain grammatical errors or
inaccuracies.
These materials are provided by SAP SE or an SAP affiliate company for informational purposes only,
without representation or warranty of any kind, and SAP SE or its affiliated companies shall not be liable
for errors or omissions with respect to the materials. The only warranties for SAP SE or SAP affiliate
company products and services are those that are set forth in the express warranty statements
accompanying such products and services, if any. Nothing herein should be construed as constituting an
additional warranty.
In particular, SAP SE or its affiliated companies have no obligation to pursue any course of business
outlined in this document or any related presentation, or to develop or release any functionality
mentioned therein. This document, or any related presentation, and SAP SE’s or its affiliated companies’
strategy and possible future developments, products, and/or platform directions and functionality are
all subject to change and may be changed by SAP SE or its affiliated companies at any time for any
reason without notice. The information in this document is not a commitment, promise, or legal
obligation to deliver any material, code, or functionality. All forward-looking statements are subject to
various risks and uncertainties that could cause actual results to differ materially from expectations.
Readers are cautioned not to place undue reliance on these forward-looking statements, which speak
only as of their dates, and they should not be relied upon in making purchasing decisions.

© Copyright. All rights reserved. iii


Typographic Conventions

American English is the standard used in this handbook.


The following typographic conventions are also used.

This information is displayed in the instructor’s presentation

Demonstration

Procedure

Warning or Caution

Hint

Related or Additional Information

Facilitated Discussion

User interface control Example text

Window title Example text

iv © Copyright. All rights reserved.


Contents

vii Course Overview

1 Unit 1: Getting Started

3 Lesson: Preparing the Development Environment


8 Lesson: Taking a First Look at ABAP
11 Exercise 1: Create an ABAP Cloud Project and Investigate ABAP
Coding
17 Lesson: Software Structure And Logistics
20 Lesson: Developing your First ABAP Program
25 Exercise 2: Create a Package and a Hello World Application

31 Unit 2: Basic Techniques and Concepts

33 Lesson: Understanding the Basics of ABAP


39 Lesson: Working With Basic Data Objects and Data Types
53 Lesson: Processing Data
59 Lesson: Working with Simple Internal Tables
67 Lesson: Using Control Structures in ABAP
79 Lesson: Debugging an ABAP Program
89 Exercise 3: Debug an ABAP Program

105 Unit 3: Local Classes

106 Lesson: Defining a local class


111 Exercise 4: Define a Local Class
115 Lesson: Creating Instances Of A Class
121 Exercise 5: Create and Manage Instances
128 Lesson: Defining And Calling Methods
139 Exercise 6: Define and Call Methods
150 Lesson: Using Encapsulation To Ensure Consistency
157 Exercise 7: Use Private Attributes and Constructors

173 Unit 4: Data Modelling and ABAP SQL

175 Lesson: Investigating a Table Definition


179 Lesson: Implementing Basic SELECT Statements
187 Lesson: Working with CDS View
193 Exercise 8: Analyze and Use a CDS View Entity

207 Unit 5: Structured Data Objects

209 Lesson: Declaring a Structured Data Object


216 Lesson: Working with Structured Data Objects
231 Exercise 9: Use a Structured Data Object

© Copyright. All rights reserved. v


243 Unit 6: Complex Internal Tables

245 Lesson: Declaring a Complex Internal Table


253 Lesson: Working with Complex Internal Tables

273 Unit 7: Database Updates Using Business Objects

275 Lesson: Analyzing a Business Object


280 Lesson: Using the Entity Manipulation Language
287 Exercise 10: Modify Data Using EML

293 Unit 8: RESTful Application Programming

295 Lesson: Introducing the ABAP RESTful Application Programming


Model (RAP)
296 Lesson: Exploring the Architecture of RAP
303 Exercise 11: Create Data Elements
305 Exercise 12: Create a Database Table
313 Exercise 13: Generate the Development Objects for an OData UI
Service
318 Lesson: Adding ABAP logic
329 Exercise 14: Validate the Semantic Key
333 Exercise 15: Validate the Airline
337 Exercise 16: Validate the Airport Codes
345 Exercise 17: Determine the Cities and Countries
349 Lesson: Improving the User Experience
353 Exercise 18: Adjust the UI of your app
361 Exercise 19: Provide Input Help

vi © Copyright. All rights reserved.


Course Overview

TARGET AUDIENCE
This course is intended for the following audiences:
● Development Consultant
● Developer

© Copyright. All rights reserved. vii


viii © Copyright. All rights reserved.
UNIT 1 Getting Started

Lesson 1
Preparing the Development Environment 3

Lesson 2
Taking a First Look at ABAP 8
Exercise 1: Create an ABAP Cloud Project and Investigate ABAP Coding 11

Lesson 3
Software Structure And Logistics 17

Lesson 4
Developing your First ABAP Program 20
Exercise 2: Create a Package and a Hello World Application 25

UNIT OBJECTIVES

● Create an ABAP Cloud project in ADT


● Work with a development object in ADT
● Create an ABAP package
● Create a Hello World Application

© Copyright. All rights reserved. 1


Unit 1: Getting Started

2 © Copyright. All rights reserved.


Unit 1
Lesson 1
Preparing the Development Environment

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Create an ABAP Cloud project in ADT

ABAP Cloud Project Creation in ADT

Figure 1: Installing Eclipse And ABAP Development Tools

To develop ABAP applications for SAP BTP, you need the Eclipse development environment.
You can download it free of charge from eclipse.org. The default Eclipse installation does not
contain the ABAP Development Tools (ADT) - you must download these separately. To do so,
open Eclipse and choose Help -> Install New Software. A dialog box appears, in which you
enter the URL, tools.hana.ondemand.com/latest. This downloads the ABAP tools and installs
them in Eclipse.
You should periodically check for updates to both Eclipse and the ABAP tools. You do this in
Eclipse by choosing Help -> Check for Updates.
To develop ABAP applications for SAP BTP, you need to first install and prepare the Eclipse
development environment. Watch this video to know how.

© Copyright. All rights reserved. 3


Unit 1: Getting Started

Video: Preparing to Develop ABAP Applications


For more information on Preparing to Develop ABAP Applications, please view
the video in the lesson Preparing the Development Environment in your online
course.

Figure 2: The ABAP Perspective

When you have installed Eclipse and ADT, you need to switch to the ABAP perspective. A
perspective in Eclipse is a window in which you can perform a certain task. The default
perspective in a fresh Eclipse installation is the Java development perspective. To develop
ABAP applications, choose Window → Perspective → Open Perspective → Other. A dialog box
appears with a list of all of the available perspectives. Double-click ABAP.
A perspective is made up of a set of views, which appear as tabs in the Eclipse window. The
most important views are the source code editor and the project explorer, which you use to
navigate between different development objects. There is a wide range of other views that you
will need, such as the Problems view to display error messages, the documentation view, and
views for searching for objects or displaying where in the system a particular object is used.

4 © Copyright. All rights reserved.


Lesson: Preparing the Development Environment

Different Types of ABAP Project

Figure 3: Different Types of ABAP Project

Eclipse as a development environment is not embedded in the ABAP system. Instead, you
have to connect to each ABAP system in which you want to work, and each connection is
represented in Eclipse by a project. There are two kinds of project in ADT - ABAP Projects,
which you use to connect to an on-premise ABAP system, and ABAP Cloud Projects, which
you use to connect either to SAP BTP ABAP or to SAP S/4HANA Cloud. Here we are only
going to discuss how to access a cloud system.

Locating the ABAP Environment

Figure 4: Locating the ABAP Environment

The SAP Business Technology Platform is SAP's platform as a service (PAAS). To access it,
you need to create a global account. There are various subscription models available,
depending on whether you need to run large-scale productive environments or just a single-
user environment for your own continuing professional development.

© Copyright. All rights reserved. 5


Unit 1: Getting Started

Within a global account, there are one or more subaccounts. Each subaccount can be
configured differently, so that a single enterprise can run several different platforms but
manage their subscription using just the single global account. Inside the subaccount, you
deploy a runtime such as Cloud Foundry or Kyma. Once you have done this, you can deploy
an ABAP instance.
In this course we are using an ABAP instance deployed on the SAP Business Technology
Platform. However, the material is also relevant for other ABAP deployments, such as an on-
premise SAP S/4HANA system or an SAP S/4HANA Cloud system.

Figure 5: Retrieving the Service Key

To log onto your ABAP instance, you will need a service key. In this course, we assume that
you have already created a suitable account on SAP BTP and that you have deployed an
ABAP instance and created the service key already. For further information, refer to https://
account.hana.ondemand.com.
To retrieve the service key, log onto your global account and navigate to the corresponding
subaccount in which the ABAP service is running. Choose Instances and Subscriptions on the
left-hand side of the screen, then scroll to Instances. You should see the ABAP instance, and
in the Credentials column, a link to the service key. Select the link to access the dialog box
shown in the figure, Creating an ABAP Cloud Project. To copy the contents of the key to the
clipboard, choose Copy JSON.

6 © Copyright. All rights reserved.


Lesson: Preparing the Development Environment

Figure 6: Creating an ABAP Cloud Project

In order to develop, you must log onto your ABAP account. To do this, choose File → New →
ABAP Cloud Project. A dialog box appears, in which you should select the option, Use a
Service Key. Choose Next, and then paste the service key that you copied from your BTP
account into the editor. Choose Next again, and then select Open Logon Page in Browser. This
connects to the BTP and authenticates you. Close the browser window and return to Eclipse.
Set the language that you want to use, and choose Finish.

LESSON SUMMARY
You should now be able to:
● Create an ABAP Cloud project in ADT

© Copyright. All rights reserved. 7


Unit 1
Lesson 2
Taking a First Look at ABAP

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Work with a development object in ADT

Investigating ABAP Coding


Working in the Project Explorer

Figure 7: The Project Explorer

To work with ABAP development objects, you usually display the contents of a package in the
project explorer. Packages are containers for development objects that logically belong
together.
Here are the steps to add a package to your favorites.
To add a package to your favorites, right-click the Favorite Packages node in the project
explorer and choose Add Package. A dialog box appears, in which you can enter a filter term.
The system then displays only the packages that contain this term. Double-click the package
that you want to add to your favorites.

Animation
For more information on this topic please view the animation in the lesson Taking
a First Look at ABAP in your online course.

8 © Copyright. All rights reserved.


Lesson: Taking a First Look at ABAP

Opening Development Objects

Figure 8: Opening Development Objects

There are two ways to open a development object in ADT.

Animation
For more information on this topic please view the animation in the lesson Taking
a First Look at ABAP in your online course.

The first is to locate the object name in the project explorer and double-click it. The other is to
use the keyboard shortcut, Ctrl + Shift + A. This opens a dialog box in which you can enter
part of the name of an object.

Investigating a Development Object

Figure 9: Investigating a Development Object

© Copyright. All rights reserved. 9


Unit 1: Getting Started

When you are working with ABAP code, there are certain function keys in ADT that will help
you.

Animation
For more information on this topic please view the animation in the lesson Taking
a First Look at ABAP in your online course.

F1
The F1 key displays the ABAP language help for the current statement. A statement is the
name for a command in ABAP.
F2
The F2 key displays information about the element on which the cursor is placed.
F3
The F3 key navigates to the definition of the object on which the cursor is placed. You can
return from there to the original object using the key combination, ALT + LEFT ARROW,
on your keyboard.

10 © Copyright. All rights reserved.


Unit 1
Exercise 1
Create an ABAP Cloud Project and Investigate
ABAP Coding

You must already have an SAP BTP account with an ABAP service and service key. You must
also have installed Eclipse and the SAP ABAP Development Tools.

Task 1: Create an ABAP Cloud Project


In your local installation of SAP ABAP Development Tools (ADT) in Eclipse, create an ABAP
Cloud Project and link it to the ABAP Instance in your SAP BTP subaccount.

1. Log on to your subaccount in SAP BTP and copy the ABAP service key into your clipboard.

2. Open Eclipse and switch to the ABAP perspective.

Task 2: Analyze ABAP Class /DMO/CL_FLIGHT_LEGACY


Use some functions of ADT to analyze the source code of ABAP class /DMO/
CL_FLIGHT_LEGACY.

Note:
You are not supposed to actually read the code you are going to see in this
exercise. Concentrate on the navigation and display functions in the development
environment.

1. Open ABAP class /DMO/CL_FLIGHT_LEGACY in the editor view.

Note:
If you cannot find class /DMO/CL_FLIGHT_LEGACY or any other development
object starting with /DMO/, you have to import the ABAP Flight
Reference Scenario for the ABAP RESTful Application
Programming Model into your system. To do so, please follow the
instructions under the following link:https://github.com/SAP-samples/abap-
platform-refscen-flight

2. Open the Properties tab to display the administrative data of development object /DMO/
CL_FLIGHT_LEGACY.

3. Locate ABAP class /DMO/CL_FLIGHT_LEGACY in the Project Explorer view on the left.

4. Find the string get_instance( )->get in the source code of ABAP class /DMO/
CL_FLIGHT_LEGACY.

© Copyright. All rights reserved. 11


Unit 1: Getting Started

Note:
There has to be exactly one blank between the brackets.

5. Navigate to the definition of code element get( .

6. A few code lines down there is a line starting with SELECT. Without navigating away,
display some information about code element /dmo/bookingafter keyword FROM.

7. Display the ABAP Language help for keyword SELECT.

12 © Copyright. All rights reserved.


Unit 1
Solution 1
Create an ABAP Cloud Project and Investigate
ABAP Coding

You must already have an SAP BTP account with an ABAP service and service key. You must
also have installed Eclipse and the SAP ABAP Development Tools.

Task 1: Create an ABAP Cloud Project


In your local installation of SAP ABAP Development Tools (ADT) in Eclipse, create an ABAP
Cloud Project and link it to the ABAP Instance in your SAP BTP subaccount.

1. Log on to your subaccount in SAP BTP and copy the ABAP service key into your clipboard.
a) Start the SAP BTP Cockpit and choose the subaccount containing your ABAP service.

b) Choose Instances and Subscriptions.

c) In the Instances box, select the Key(s) entry under Credentials.

d) Choose Copy JSON, and then select Close.

2. Open Eclipse and switch to the ABAP perspective.


a) Open Eclipse and close all tabs.

b) Choose Window → Perspective → Open Perspective → Other.

c) In the dialog box, double-click ABAP.

d) Choose File → New → ABAP Cloud Project.

e) Select Use a Service Key and choose Next

f) Paste the service key into the editor with the key combination, Ctrl + V, and choose
Next.

g) Choose Open Logon Page in Browser. When you see the message, You have been
successfully logged on, close the browser window and return to Eclipse.

h) To finish creating the project, choose Finish.

Task 2: Analyze ABAP Class /DMO/CL_FLIGHT_LEGACY


Use some functions of ADT to analyze the source code of ABAP class /DMO/
CL_FLIGHT_LEGACY.

Note:
You are not supposed to actually read the code you are going to see in this
exercise. Concentrate on the navigation and display functions in the development
environment.

1. Open ABAP class /DMO/CL_FLIGHT_LEGACY in the editor view.

© Copyright. All rights reserved. 13


Unit 1: Getting Started

Note:
If you cannot find class /DMO/CL_FLIGHT_LEGACY or any other development
object starting with /DMO/, you have to import the ABAP Flight
Reference Scenario for the ABAP RESTful Application
Programming Model into your system. To do so, please follow the
instructions under the following link:https://github.com/SAP-samples/abap-
platform-refscen-flight

a) In the Eclipse menu, choose Navigate → Open ABAP Development Object ... or press
Ctrl + Shift + A

b) In the input field, enter /DMO/CL_FLIGHT as search string.

c) In the list of matching items, click on /DMO/CL_FLIGHT_LEGACY (Global Class) and


choose OK.

2. Open the Properties tab to display the administrative data of development object /DMO/
CL_FLIGHT_LEGACY.
a) Place the cursor anywhere in the source code of class /DMO/CL_FLIGHT_LEGACY.

b) In the tab strip below the editor view, navigate to tab Properties.

c) Analyze the administrative data that are displayed there, for example the original
language, the time stamp of the last change or the user that at first created the object.

3. Locate ABAP class /DMO/CL_FLIGHT_LEGACY in the Project Explorer view on the left.
a) Place the cursor anywhere in the source code of class /DMO/CL_FLIGHT_LEGACY.

b) On the tool bar of the project explorer, choose Link with Editor. This should expand a
part of the tree under your ABAP project with ABAP class /DMO/CL_FLIGHT_LEGACY
as its end point.

4. Find the string get_instance( )->get in the source code of ABAP class /DMO/
CL_FLIGHT_LEGACY.

Note:
There has to be exactly one blank between the brackets.

a) Place the cursor anywhere in the source code of class /DMO/CL_FLIGHT_LEGACY.

b) Press Ctrl + F to open the Find/Replace dialog.

c) In the input field labelled with Find: enter get_instance( )->get and choose Find.

5. Navigate to the definition of code element get( .


a) In the current code line, place the cursor on get( and choose Navigate → Navigate to.
Alternatively, press F3.

6. A few code lines down there is a line starting with SELECT. Without navigating away,
display some information about code element /dmo/bookingafter keyword FROM.
a) In the code line starting with SELECT, place the cursor on /dmo/booking and choose
Source Code → Show Code Element Information. Alternatively, press F2.

14 © Copyright. All rights reserved.


Lesson: Taking a First Look at ABAP

7. Display the ABAP Language help for keyword SELECT.


a) At the beginning of the current code line, place the cursor on SELECT and choose
Source Code → Show ABAP Language Help. Alternatively, press F1.

Note:
There is no need to read or understand the documentation at this point. If
you are familiar with Structured Query Language (SQL) you can have a look
at the first paragraph in section Effect.

© Copyright. All rights reserved. 15


Unit 1: Getting Started

LESSON SUMMARY
You should now be able to:
● Work with a development object in ADT

16 © Copyright. All rights reserved.


Unit 1
Lesson 3
Software Structure And Logistics

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Create an ABAP package

ABAP Package Creation


Organizing Development

Figure 10: Organizing Development

When you create a development object in the ABAP environment, you must assign it to a
package. Packages serve as containers for all of the development objects that logically belong
together. Each package is also assigned to a software component. The complete set of
development objects in the system is referred to as the ABAP Repository. Consequently,
development objects are also often called repository objects.
You develop your applications in a development environment, but must then ensure that they
can be tested in an appropriate test environment before being moved on to the production
environment. Typically, you will have a single global account and a subaccount for each of the
development, test, and production environments. Software components allow you to
transport your objects.

© Copyright. All rights reserved. 17


Unit 1: Getting Started

Transport Request

Figure 11: Transport Request

When you create a new development object or change an existing one, you must assign it to a
transport request. Transport requests ensure that all development objects that logically
belong together are transported together into the test, and subsequently the production
system.
Each transport request has an owner, and the owner can assign other users to the request. In
this way, transport requests support team development.
When an object is included in a transport request, it is locked. This means that it can only be
edited by a user who is assigned to the same request.
When work on all of the objects in the request is finished, all of the developers assigned to it
must release their work. After this, the owner of the request can release the entire request. If
the transport request belongs to a transportable software component, the system
administrator can import it into the test system for testing.
When you release any kind of transport request, the system releases the locks on the objects
in the request, so that any developer can access them again.
To learn how to create an ABAP package, refer to the demonstration, How to Create a
Package.

18 © Copyright. All rights reserved.


Lesson: Software Structure And Logistics

Figure 12: Creating a Package

To create a new package, choose File → New → ABAP Package. Enter the name of the
package, which must begin with the letter Z or Y. This is a requirement for all ABAP
development in the customer name-space, and serves to avoid naming collisions, as objects
delivered by SAP never use Z or Y as the first character of the name. Enter a description for
the package, and choose Next.
In the next dialog box, you must assign the package to a software component. Since you are
creating practice objects that are not intended for productive use, enter the software
component ZLOCAL and choose Next.

Figure 13: Assigning A Package To A Transport Request

You must assign your package to a transport request. As you have not yet worked with
transport requests, select Create a new request. Enter a description for the transport request
and choose Finish.
You are now ready to start developing. You will assign all of the further objects that you create
to your package and to the same transport request.

LESSON SUMMARY
You should now be able to:
● Create an ABAP package

© Copyright. All rights reserved. 19


Unit 1
Lesson 4
Developing your First ABAP Program

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Create a Hello World Application

Creating a Hello World App

Figure 14: The Hello World App

As in all other programming languages, the first thing that you should do in ABAP is familiarize
yourself with the development environment and the most elementary aspects of the language
by writing a short “Hello World” app.
The main user interface technology that you will use in modern ABAP programming is Fiori
Elements. However, ADT provides a console for you to create output quickly and simply in
test applications.

20 © Copyright. All rights reserved.


Lesson: Developing your First ABAP Program

Figure 15: Creating a Class

You will write your ABAP code in a class. To create one, choose File → New → ABAP Class. A
dialog box appears. Ensure that the project is correct, and enter the name of the package that
you have already created.
Next you must name your class, following ABAP naming conventions; the name of the class
must start with Z or Y to avoid naming collisions with SAP's own objects. Naming conventions
also require that the name of the class is also prefixed with CL for class.
Following the prefix ZCL, enter the actual name of the class. This should be as easily
understandable as possible. The name of the class (including prefix) can be up to 30
characters long and may consist of the letters A-Z, the digits 0-9, and the underscore symbol
_. You use the underscore to separate the individual words that you use in the name of the
class.

Figure 16: Adding The Interface IF_OO_ADT_CLASSRUN

Once you have entered the name of your class, choose Add to add an interface to a class.
Interfaces ensure that a user of the class can use it in a particular way. The interface
IF_OO_ADT_CLASSRUN ensures that the development environment can run the class and
display output in the Eclipse console. In the Add ABAP Interface dialog box, use the filter field
to restrict the number of entries in the hit list. Once the interface IF_OO_ADT_CLASSRUN is
displayed, double-click it. When you return to the New ABAP Class dialog box, the interface
appears in the list of interfaces.
Choose Next.

© Copyright. All rights reserved. 21


Unit 1: Getting Started

Figure 17: Assigning the Class to a Transport Request

On the last screen, you assigned the class to a package. Now you must assign it to a transport
request. Under Choose from requests in which I am involved, mark the request that you used
to create your package and choose Finish.

Figure 18: Editing the Class

The interface IF_OO_ADT_CLASSRUN allows you to run a class in ADT using the F9 key. When
you do so, the system executes the code between METHOD if_oo_adt_classrun~main and
ENDMETHOD. In this code block you can output information in the ADT console.

Figure 19: Using out->write( )

In your code block, you can use out->write( ) to display information in the console. The line
out->write( “Hello World”). prints Hello World to the console. Crucially, you do not have to
know at this point how it works, you just have to type in the code, ensuring the following:

22 © Copyright. All rights reserved.


Lesson: Developing your First ABAP Program

● There is no space between write and the opening parenthesis


● There is at least one space after the opening parenthesis
● There is at least one space before the closing parenthesis
● There is a period at the end of the line.

Figure 20: Making Mistakes

When you write ABAP code, you will inevitably make mistakes. ADT checks your code as you
go along, and flags up errors in the left-hand margin of the editor with a white cross on a red
background.
You can see the corresponding error messages in the Problems view below the editor. ADT
also displays the same message as a pop-up if you move the mouse over the error symbol in
the editor.

Figure 21: Activating the Class

In order to run an ABAP object, you must activate it. To do this, choose the Activate icon in
the toolbar or use the keyboard shortcut Ctrl + F3. You can see whether an object is active
or not by looking in the Properties view, usually located in the tab below the ABAP Editor.
During the activation, the system compiles the object into a form that the ABAP runtime
system can understand.

© Copyright. All rights reserved. 23


Unit 1: Getting Started

Figure 22: Running the Class

To run the class, press F9 or right-click in the editor and choose Run as → ABAP Application
(Console). The output “Hello World” appears in the console. If you cannot see the console
view, choose Window → Show View → Other... and select the Console view.

24 © Copyright. All rights reserved.


Unit 1
Exercise 2
Create a Package and a Hello World
Application

Task 1: Create a Package


Create an ABAP package in which you can store the development objects, that you will create
during this class. Add the package to your favorites so you can easily access it anytime.

1. Create ABAP package ZS4D400_##, where ## is your group number. Assign the package
to the software component ZLOCAL. When you are prompted to assign the package to a
transport request, create a new one.

2. Add the package to your favorites.

Task 2: Create a Hello World Application


In your package, create an new ABAP class. Let the class implement interface
IF_OO_ADT_CLASSRUN so that you can use the class as main program for an Eclipse console
app.

1. In your package, create a new ABAP class with the name ZCL_##_HELLO_WORLD. Ensure
that it uses the interface IF_OO_ADT_CLASSRUN. When you are prompted to assign the
class to a transport request, use the transport request that you created in the previous
task.

2. In the if_oo_adt_classrun~main( ) method, use out->write( ) to output the


phrase Hello World.

3. Activate and test your class.

4. Check the output in the Console view of eclipse.

© Copyright. All rights reserved. 25


Unit 1
Solution 2
Create a Package and a Hello World
Application

Task 1: Create a Package


Create an ABAP package in which you can store the development objects, that you will create
during this class. Add the package to your favorites so you can easily access it anytime.

1. Create ABAP package ZS4D400_##, where ## is your group number. Assign the package
to the software component ZLOCAL. When you are prompted to assign the package to a
transport request, create a new one.
a) Choose File → New → ABAP Package.

b) Enter the name ZS4D400_##, where ## is your group number.

c) Enter a description for your package.

d) Choose Next.

e) Enter the software component, ZLOCAL, and choose Next.

f) Mark Create a new request and enter a description for the new transport request.

g) Choose Finish.

2. Add the package to your favorites.


a) Expand your ABAP project tree until you can see the node Favorite Packages.

b) Right-click and choose Add Package.

c) In the dialog box, enter the package name ZS4D400_##, where ## is your group
number.

d) Double-click the name of the package in the hit list to add it to your list of favorite
packages.

Task 2: Create a Hello World Application


In your package, create an new ABAP class. Let the class implement interface
IF_OO_ADT_CLASSRUN so that you can use the class as main program for an Eclipse console
app.

1. In your package, create a new ABAP class with the name ZCL_##_HELLO_WORLD. Ensure
that it uses the interface IF_OO_ADT_CLASSRUN. When you are prompted to assign the
class to a transport request, use the transport request that you created in the previous
task.
a) Choose File → New → ABAP Class.

b) Enter your package ZS4D400_##, where ## is your group number.

26 © Copyright. All rights reserved.


Lesson: Developing your First ABAP Program

c) Enter the name ZCL_##_HELLO_WORLDwhere ## is your group number, and enter a


description for your class.

d) Choose Add... (next to the Interfacesgroup box).

e) Enter the filter text IF_OO_ADT_CLASSRUN. Double-click the matching entry in the hit
list.

f) Choose Next.

g) Mark Choose from requests in which I am involved and your own transport request.

h) Choose Finish.

2. In the if_oo_adt_classrun~main( ) method, use out->write( ) to output the


phrase Hello World.
a) In the editor, enter the following coding between METHOD
if_oo_adt_classrun~main and ENDMETHOD.:
out->write( 'Hello World' ).

3. Activate and test your class.


a) Activate the class with the keyboard shortcut Ctrl + F3.

b) Run the class with the F9 key.

4. Check the output in the Console view of eclipse.


a) Check the Console view that should have opened as a new tab below the editor view.

b) If the Console view is not visible, open it by choosing Window → Show view → Other.
Double-click Console in the hit list.

© Copyright. All rights reserved. 27


Unit 1: Getting Started

LESSON SUMMARY
You should now be able to:
● Create a Hello World Application

28 © Copyright. All rights reserved.


Unit 1

Learning Assessment

1. An ABAP Cloud Project in ABAP Development Tools (ADT) allows you to connect to what
kinds of system?
Choose the correct answers.

X A SAP BTP ABAP instance

X B On-Premise ABAP system

X C Embedded ABAP instance in SAP S/4HANA Cloud

2. In ABAP source code, how do you navigate to the definition of a development object?
Choose the correct answer.

X A Double-click the name of the object

X B Position the cursor on the name of the object and press F2

X C Position the cursor on the name of the object and press F3

3. What must you do when you create an ABAP package?


Choose the correct answers.

X A Use the letter Z or Y as the first character in the name

X B Assign the package to an application component

X C Assign the package to a software component

X D Declare what other packages can use the contents of the package.

4. Which of the following characters is not allowed in the name of an ABAP class?
Choose the correct answer.

X A 8

X B _

X C $

© Copyright. All rights reserved. 29


Unit 1: Learning Assessment

30 © Copyright. All rights reserved.


UNIT 2 Basic Techniques and Concepts

Lesson 1
Understanding the Basics of ABAP 33

Lesson 2
Working With Basic Data Objects and Data Types 39

Lesson 3
Processing Data 53

Lesson 4
Working with Simple Internal Tables 59

Lesson 5
Using Control Structures in ABAP 67

Lesson 6
Debugging an ABAP Program 79
Exercise 3: Debug an ABAP Program 89

UNIT OBJECTIVES

● Describe the evolution of ABAP


● Describe the basics of ABAP syntax
● Declare data objects
● Assign values
● Perform arithmetic calculations
● Apply string processing
● Define simple internal tables
● Process data using simple internal tables

© Copyright. All rights reserved. 31


Unit 2: Basic Techniques and Concepts

● Implement conditional branching


● Implement Iterations
● Handle Exceptions
● Enter debugging mode
● Control the execution of code
● Analyze the content of data objects

32 © Copyright. All rights reserved.


Unit 2
Lesson 1
Understanding the Basics of ABAP

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Describe the evolution of ABAP
● Describe the basics of ABAP syntax

Understanding ABAP Then And Now


Origin and Evolution of ABAP

Figure 23: Origin and Evolution of ABAP

ABAP is a programming language developed by SAP for the development of business


applications in the SAP environment.
When ABAP was first published in 1983, it was designed as a procedural programming
language based on statements. Although relatively independent, it was influenced by other
popular programming languages of the time, mostly COBOL and Pascal.
By the end of the 1990s, the ABAP language was extended to allow for object-oriented
programming. Important concepts of popular object-oriented programming languages, like C
++ and Java, were integrated into the ABAP language. ABAP Objects, as the programming
language was called now, combined procedural and object-oriented parts in one language.
Even though ABAP allowed for object-oriented programming, the syntax remained dominated
by statements. Compared to other modern programming languages, like Java and C#, ABAP
code appeared lengthy, complicated and involved a lot of helper variables to link the various
statement. To amend this, ABAP was extended with modern expressions to replace or extend

© Copyright. All rights reserved. 33


Unit 2: Basic Techniques and Concepts

the existing statements. Again, ABAP combines traditional statement-based syntax elements
and modern, expression-based syntax elements in one programming language.
For new ABAP developments, we recommended using object-oriented and expression-based
syntax elements wherever possible.
Watch this video to know how ABAP has evolved over the years.

Video: Origin and Evolution of ABAP


For more information on Origin and Evolution of ABAP, please view the video in
the lesson Understanding the Basics of ABAP in your online course.

Figure 24: ABAP Language Versions

Each ABAP program has the program attribute “ABAP language version”, which is defined
internally by a version ID. The version of a program determines which language elements and
which repository objects can be used in the program and which syntax rules apply. The
following versions are currently available:
Let's explore the available ABAP language versions.

Animation
For more information on this topic please view the animation in the lesson
Understanding the Basics of ABAP in your online course.

Note:
This course gives a universal introduction to ABAP development. It restricts itself
to syntax elements and language features available in all three language versions.
An exception is the introduction to the ABAP RESTful Application Programming
Model which is not part of ABAP for key users.

34 © Copyright. All rights reserved.


Lesson: Understanding the Basics of ABAP

Describing The Basics Of ABAP Syntax


Some Basic Features of the ABAP Language

Figure 25: Some Basic Features of the ABAP Language

Animation
For more information on this topic please view the animation in the lesson
Understanding the Basics of ABAP in your online course.

Examples of ABAP Syntax

Figure 26: Examples of ABAP Syntax

These code examples illustrate some of the basic features of the ABAP programming
language. The upper code consists of three statements, each of them ends with a period (.) .

© Copyright. All rights reserved. 35


Unit 2: Basic Techniques and Concepts

The DATA statement is a declarative statement to define variables. The CONCATENATE


statement is a data processing statement for combining char-like data.
The lower code example consists of four statements.
The lower code consists of four value assignments. The name of the target variable (text) is
followed by the equals sign (=) that serves as the assignment operator. The operand position
on the right-hand side is occupied by expressions of different complexity: A literal, a variable,
a string processing function (replace), and an expression for a conditional assignment
(COND).

Comments in ABAP

Figure 27: Comments in ABAP

A comment in a programming language is a piece of source code that is ignored by the


compiler or interpreter
In ABAP, there are two ways to define a piece of source code as comment:
● A star sign (*) in the first column identifies the entire line as a comment
● A double quote (") sign identifies the rest if the line, that is, the code to the right, as
comment.

Note:
You can place the " sign in any column. The star sign (*) only works if placed in the
first column. In other positions it causes a syntax error, unless it is a syntactically
correct part of an ABAP statement.

Hint:
To comment one or several code lines, that is, to add star sign (*) in the first
column, select the code lines and press Ctrl + <. Alternatively, from the
context menu, you can choose Source Code → Add Comment. To uncomment
the selected code lines, that is, to remove the star sign (*) from the first column,
press Ctrl + > or choose Souce Code → Remove Comment from the context
menu.

36 © Copyright. All rights reserved.


Lesson: Understanding the Basics of ABAP

Watch this video to learn about comments in ABAP.

Video: Comments in ABAP


For more information on Comments in ABAP, please view the video in the lesson
Understanding the Basics of ABAP in your online course.

LESSON SUMMARY
You should now be able to:
● Describe the evolution of ABAP
● Describe the basics of ABAP syntax

© Copyright. All rights reserved. 37


Unit 2: Basic Techniques and Concepts

38 © Copyright. All rights reserved.


Unit 2
Lesson 2
Working With Basic Data Objects and Data
Types

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Declare data objects
● Assign values

Data Objects in ABAP

Figure 28: Data Objects in ABAP

A data object in an ABAP program represents a reserved section of the program memory.
ABAP knows three types of data objects: Variables, Constants, and Literals.

Variables
A variable is a data object with content that can change during runtime. A variable is
identified by a name. The name is also used to address the data object at runtime. The
starting value of an ABAP variables is always well-defined.
Constants
Constants are similar to variables. But in contrast to variables the value is hard coded in
the source code and must not change during runtime. Like variables, constants have a
name by which they can be re-used.
Literals

© Copyright. All rights reserved. 39


Unit 2: Basic Techniques and Concepts

The value of literals is also hard-coded in the source code. In contrast to constants,
literals don't have a name. Because of that you cannot reuse a literal. Only use literals to
specify the values for constants and the starting values for variables.

ABAP data objects are always typed: Every data object is based on a data type which
determines the kind of information they can contain. The data type of an ABAP data object
stays the same throughout a program execution.

Declaration of Variables

Figure 29: Declaration of Variables

A variable in an ABAP program is declared with keyword DATA.


A DATA statement consists of three parts. Let's look at each part in more detail.
A DATA statement consists of the following parts:

DATA
Keyword DATA is followed by the name of the variable. The name of a variable may be up
to 30 characters long. It may contain the characters A-Z, the digits 0-9, and the
underscore character. The name must begin with a letter or an underscore.
TYPE
The type of the variable is specified after addition TYPE. In the example, built-in types i
(for integer numbers) and string (character string with variable length) are used.
VALUE
Addition VALUE is optional and you can use it to specify a start value for the variable. If
VALUE is missing, the variable is created with an initial value that depends on the
technical type of the variable.

Animation
For more information on this topic please view the animation in the lesson
Working With Basic Data Objects and Data Types in your online course.

40 © Copyright. All rights reserved.


Lesson: Working With Basic Data Objects and Data Types

Sources of ABAP Data Types

Figure 30: Sources Of ABAP Data Types

ABAP offers the following sources of Data Types:

ABAP Built-in
ABAP has a set of 13 predefined data types for simple numeric, char-like, and binary data
objects.
TYPES Statement
Statement TYPES allows you to define data types and reuse them in different places,
depending on the location of the definition.
ABAP Dictionary
The ABAP Dictionary is a part of the ABAP Repository. Among other things, it manages
global data types which are available throughout the system. ABAP Dictionary types not
only define technical properties, they add semantic information, for example, labels.
ABAP Dictionary types are particularly useful when implementing user interfaces.

ABAP offers different sources of data types.

Animation
For more information on this topic please view the animation in the lesson
Working With Basic Data Objects and Data Types in your online course.

© Copyright. All rights reserved. 41


Unit 2: Basic Techniques and Concepts

Predefined ABAP Types

Figure 31: Some Predefined ABAP Types

Some important ABAP types are listed in the figure, Some Predefined ABAP Types. For some
of these types you can add addition LENGTH to specify a fixed length. These types are called
incomplete types. In the case of type P, you may also specify a number of decimal places. The
ABAP types for which additions LENGTH and DECIMALS are not supported are called
complete types.

Complete ABAP Types


TYPE STRING
A field of type string is a character-like field of variable length. The ABAP runtime system
allocates and releases memory to optimize the management of string variables. You
cannot influence this behavior directly. The maximum length of a string is governed by
settings that the system administrator makes. However, in practice, we talk about strings
being unlimited in length.
TYPE I
A field of type I is a numeric field that contains a whole number. The system allocates 4
bytes (32 bits) for such a field which allows for values between - 2^31 and + 2^31.
TYPE D
A field of type D represents a date. In ABAP, the date always has the format YYYYMMDD
(without separators). The system converts this format according to the current locale
before the value is displayed on the user interface. Likewise, when the user enters a date,
the system converts it into the ABAP format before you start to process it.

TYPE T
A field of type Type T represents a time. In ABAP, this has the format HHMMSS (without
separators in 24 hour format). If the current locale uses 12 hour format, the system
converts the values automatically.

Incomplete ABAP Types


Type C

42 © Copyright. All rights reserved.


Lesson: Working With Basic Data Objects and Data Types

A field of type C is a character-like field of specific length. You specify its length in
characters; the runtime system then assigns double the number of bytes in order to
accommodate the field. You use this type when a fixed length is important.
Type N
A field of type N is a character field of specific length that only contains digits. This field
should contain sequence of digits that you do not want to regard as a number and
perform calculations with. For example, this could be a personnel number or cost center.
Type P
A field of type P (P for “packed number”) is a field that contains a numeric value with a
specified number of digits and decimal places. Use this type for numbers with decimal
places or where the value range type I is not sufficient.

Try It Out: Some Predefined ABAP TYPES


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Data Objects with Built-in Types


**********************************************************************

" comment/uncomment the following declarations and check the output


DATA variable TYPE string.
* DATA variable TYPE i.
* DATA variable TYPE d.
* DATA variable TYPE c LENGTH 10.
* DATA variable TYPE n LENGTH 10.
* DATA variable TYPE p LENGTH 8 DECIMALS 2.

* Output
**********************************************************************

out->write( 'Result with Initial Value)' ).


out->write( variable ).
out->write( '---------' ).

variable = '19891109'.

out->write( 'Result with Value 19891109' ).


out->write( variable ).
out->write( '---------' ).

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Analyze the console output. Uncomment different declarations of variable. Try your
own declarations to get familiar with the concepts.

© Copyright. All rights reserved. 43


Unit 2: Basic Techniques and Concepts

Local Types and Global Types

Figure 32: Type Definition with Statement TYPES

Instead of using built-in types in the DATA statement directly, you can use statement TYPES
to define the type first. You can then use the type in a DATA statement after the TYPE
addition.

Figure 33: Data Elements in the ABAP Dictionary

In an SAP system, there are thousands of business entities, such as country code, plant,
material number, fiscal year, cost center, and so on. Technically, it would be possible to define
these entities in every single program using the built-in ABAP types that you have just seen.
However, this would be extremely labor-intensive and error-prone. Instead, SAP provides the
ABAP Dictionary, which is a central store for important data types and also the tool that you
use to create database tables.
In the ABAP Dictionary, single business entities are described by data elements. In the
example, variable airport is typed with data element /DMO/AIRPORT_ID.

44 © Copyright. All rights reserved.


Lesson: Working With Basic Data Objects and Data Types

When you press the F2 key to display the details of this data type you can see that technically
this type is a character of length 3. In addition, the data element provides the description
“Flight Reference Scenario: Airport ID” and four field labels of different length.
When you press the F3 key to navigate to the definition of the type, a new view opens with the
editor for data elements.

Constants and Literals


Declaration of Constants

Figure 34: Declaration of Constants

A constant is a data object with a hard-coded value that must not be changed during runtime.
Any write access to a constant leads to a syntax error.
In ABAP, you declare a constant using keyword CONSTANTS. A CONSTANT statement
consists of the same parts as a DATA statement. The only difference is, that the VALUE
addition is mandatory.
You can use the VALUE addition in the special form VALUE IS INITIAL, if the value of the
constant should be the type-specific initial value.

Literals in ABAP

Figure 35: Literals in ABAP

© Copyright. All rights reserved. 45


Unit 2: Basic Techniques and Concepts

Literals are anonymous data objects with a hard-coded value. Literals are often used to define
non-initial values for constants and non-initial starting values for variables.
Technically, you can use literals anywhere in your code. To support readability and
maintainability, it is recommended to define and use constants, instead.

Animation
For more information on this topic please view the animation in the lesson
Working With Basic Data Objects and Data Types in your online course.

ABAP knows three types of literals:


● Number Literals are integer numbers with or without sign. Number literals usually have
data type I. Only if the value is too large for data type I, type P is used, with a sufficient
length and without decimal places.
● Text Literals are character strings in simple quotes. Text literals have type C. The length is
derived from the content in quotes. Trailing blanks are ignored.
● String Literals are character strings in a pair of back quotes (`). String literals are of type
STRING. They should be used to provide values for string typed data objects.

Try It Out: Data Objects


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Example 1: Local Types


**********************************************************************

* Comment/Uncomment the following lines to change the type of my_var


TYPES my_type TYPE p LENGTH 3 DECIMALS 2.
* TYPES my_type TYPE i .
* TYPES my_type TYPE string.
* TYPES my_type TYPE n length 10.

* Variable based on local type


DATA my_variable TYPE my_type.

out->write( `my_variable (TYPE MY_TYPE)` ).


out->write( my_variable ).

* Example 2: Global Types


**********************************************************************

* Variable based on global type .


" Place cursor on variable and press F2 or F3
DATA airport TYPE /dmo/airport_id VALUE 'FRA'.

out->write( `airport (TYPE /DMO/AIRPORT_ID )` ).


out->write( airport ).

* Example 3: Constants
**********************************************************************

46 © Copyright. All rights reserved.


Lesson: Working With Basic Data Objects and Data Types

CONSTANTS c_text TYPE string VALUE `Hello World`.


CONSTANTS c_number TYPE i VALUE 12345.

"Uncomment this line to see syntax error ( VALUE is mandatory)


* constants c_text2 type string.

out->write( `c_text (TYPE STRING)` ).


out->write( c_text ).
out->write( '---------' ).

out->write( `c_number (TYPE I )` ).


out->write( c_number ).
out->write( `---------` ).

* Example 4: Literals
**********************************************************************

out->write( '12345 ' ). "Text Literal (Type C)


out->write( `12345 ` ). "String Literal (Type
STRING)
out->write( 12345 ). "Number Literal (Type I)

"uncomment this line to see syntax error (no number literal with
digits)
* out->write( 12345.67 ).

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Play around with the source code to get familiar with the concepts.

● Uncomment different declarations of my_type and use F2 and F3 to analyze the


definition of variable my_variable.

● Use F2 and F3 to analyze the definition of variable airport.

● Uncomment the definition of constant c_text2 to see the syntax error.

● Uncomment the last code line to see the syntax error.

● ...

© Copyright. All rights reserved. 47


Unit 2: Basic Techniques and Concepts

Assigning Values to Data Objects

Figure 36: Value Assignments and Expressions

Use value assignments to change the value of variables.


In ABAP, the operator for value assignments is a simple equals sign ( = ). The variable on the
left hand side is filled with the value of the expression on the right-hand side.
The simplest possible expression is a single data object, for example a literal or another
variable. But ABAP supports more sophisticated expressions too, like the arithmetic
expression in the example.
Watch this video to see how.

Video: Value Assignments and Expressions


For more information on Value Assignments and Expressions, please view the
video in the lesson Working With Basic Data Objects and Data Types in your
online course.

48 © Copyright. All rights reserved.


Lesson: Working With Basic Data Objects and Data Types

Implicit Type Conversions

Figure 37: Implicit Type Conversions

As shown in the figure, if possible, try to avoid type conversions for the following reasons:
● Additional Runtime consumption: Values with type conversions require more runtime than
value assignments with identical types.
● Potential Runtime Errors: Some combinations of source type and target type can lead to
runtime errors. If, for example, the target variable has a numeric type l and the source
expression has a character like type, then the runtime will raise an error if it cannot
translate the text into a number.
● Potential Information Loss: Some combinations of source type and target type do not
cause runtime errors but can lead to a loss of data. If, for example, source and target are of
both of type C but the type of the target variable is shorter. Then the runtime simply
truncates the value of the source.

Resetting Variables

Figure 38: Resetting Variables

© Copyright. All rights reserved. 49


Unit 2: Basic Techniques and Concepts

Note:
The CLEAR statement disregards the starting value from the VALUE addition.
After CLEAR the variable always contains the type-specific initial value.

Inline Declarations in Value Assignments

Figure 39: Inline Declarations in Value Assignments

Until now, we used the DATA statement to explicitly declare our variables before we used
them in executable coding.
As an alternative, you can declare a variable at the place where you first fill it with data. We call
this an Inline Declaration. For an inline declaration you surround the name of the new variable
with brackets and add keyword DATA before the opening bracket.

Note:
No blanks are allowed inside the brackets or between DATA and the opening
bracket.

After the inline declaration, you can use the variable just like any explicitly declared variable.
The ABAP compiler derives the type for the inline declared variable from the context of the
operand position. If, for example, an inline declaration is used on the left hand side of a value
assignment the type of the new variable is the same as the type of the expression on the right-
hand side.
In the example shown in the figure Inline Declarations in Value Assignments, my_var1 is of
type string, because that is the type of the string literal on the right hand side. The other three
variables are of type integer.
Watch this video to learn about inline declarations and how they work in value assignments.

50 © Copyright. All rights reserved.


Lesson: Working With Basic Data Objects and Data Types

Video
For more information on this topic please view the video in the lesson Working
With Basic Data Objects and Data Types in your online course.

LESSON SUMMARY
You should now be able to:
● Declare data objects
● Assign values

© Copyright. All rights reserved. 51


Unit 2: Basic Techniques and Concepts

52 © Copyright. All rights reserved.


Unit 2
Lesson 3
Processing Data

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Perform arithmetic calculations
● Apply string processing

Arithmetic Calculations
Arithmetic Expressions

Figure 40: Arithmetic Expressions

Arithmetic expressions are ABAP expressions with a combination of values, operators, and
functions that the runtime system processes to calculate a result. For arithmetic expressions
the result type depends on the type of the operands used as input to the expression.
You can use an arithmetic expression in any reading operand position, for example, the right-
hand side of a value assignment.
The first example is a simple addition. The contents of amount1 and amount2 are added
together and the result placed in variable total.
The second example is a bit more sophisticated. Before adding them, the contents of
amount1 and amount2 are weighed with factors 2 and 3. The result of this addition is then
divided by 5 to calculate a weighed average.
For basic arithmetic, ABAP provides the operators + for addition, - for subtraction, * for
multiplication and / for division. Additionally, you can use the operators DIV for whole-number

© Copyright. All rights reserved. 53


Unit 2: Basic Techniques and Concepts

division and MOD for the whole-number remainder of a division. Thus, 6 DIV 4 is 1, and 6 MOD
4 is 2.
ABAP has a range of built-in functions for various tasks. Many of these are used for string
processing, but here you can see some examples for numeric functions. You use sqrt( )
function to pull the square root and ipow( ) function to raise a number to a whole-numbered
power.
In complex expressions involving more than one operator, multiplication and division take
precedence over addition and subtraction. Expressions with identical precedence are
processed from left to right.

Note:
ABAP syntax requires at least one blank between operators and operands. 1 + 1 is
correct. 1+1 leads to a syntax error.
Blanks are also needed after opening brackets and before closing brackets.

The following video illustrates the basics of arithmetic expressions.

Video: Arithmetic Expressions


For more information on Arithmetic Expressions, please view the video in the
lesson Processing Data in your online course.

Try It Out: Arithmetic Calculations


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Declarations
**********************************************************************

" comment/uncomment these line for different result types


TYPES t_result TYPE p LENGTH 8 DECIMALS 2.
* TYPES t_result TYPE p LENGTH 8 DECIMALS 0.
* TYPES t_result TYPE i.

DATA result TYPE t_result.

* Calculations
**********************************************************************
" comment/uncomment these lines for different calculations

result = 2 + 3.
* result = 2 - 3.
* result = 2 * 3.
* result = 2 / 3.
*
* result = sqrt( 2 ).
* result = ipow( base = 2 exp = 3 ).
*
* result = ( 8 * 7 - 6 ) / ( 5 + 4 ).

54 © Copyright. All rights reserved.


Lesson: Processing Data

* result = 8 * 7 - 6 / 5 + 4.

* Output
**********************************************************************

out->write( result ).

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Play around with the source code to get familiar with the concepts.

● Uncomment different calculations and type definitions.

● Implement your own calculations.

Processing Strings

Figure 41: String Templates

String templates are ABAP expressions of result type string. You can use string templates in
any reading operand position, for example, the right-hand side of a value assignment.
A string template begins and ends with a pipe-symbol ( | ). The simplest possible string
template contains nothing but literal text. In this form a string template is not really different
from a string literal.
What distinguishes a string template from a string literal is the ability to embed expressions.
An embedded expression is an ABAP expression surrounded by a pair of curly brackets
( { and } ). At runtime, ABAP evaluates the embedded expression and translates the result into
a string. In the final result, this string replaces the embedded expression (together with the
surrounding curly brackets).

Note:
ABAP syntax requires at least one blank after the opening bracket and at least one
blank before the closing bracket.

Of course one string template can contain more than one embedded expression.

© Copyright. All rights reserved. 55


Unit 2: Basic Techniques and Concepts

Inside the curly brackets you can place any kind of ABAP expression: arithmetic expressions,
like in the example above, but single variables or even literals can serve as embedded
expressions.
Let's see how can process strings using ABAP.

Animation
For more information on this topic please view the animation in the lesson
Processing Data in your online course.

Figure 42: Format Options in String Templates

One important use case for string templates is the controlled formatting of data for output.
In the first example, variable the_date is of type d and contains a date in the internal (raw)
format YYYYMMDD (where YYYY stands for the year, MM for the two-digit month and DD for
the two-digit date). When you use variable the_date as embedded expression in a string
template the result will be the same as the internal format. But when you add format option
DATE = <date_format> within the curly brackets, the system will format the value as a date. If
you add DATE = ISO, the output will be in ISO format. With DATE = USER the output format
depends on the user settings of the current user.
The second example illustrates some of the options you can use for formatting numbers.
Using NUMBER you control the general formatting of numbers, for example, whether a
decimal point is used or a decimal comma. Using SIGN you control the position of the sign and
whether a plus sign (+) is displayed or not. Using STYLE you can choose from several pre-
defined styles, like a scientific style or an engineering style.

56 © Copyright. All rights reserved.


Lesson: Processing Data

Figure 43: Joining Strings

You can join fields together using the concatenation operator &&. You can join any
combination of data objects and string expressions.
The constituent parts of the expression are joined with no space or other separator between
them. If you need spaces or another separator character, you must remember to insert it
yourself as part of the expression as shown in the second example.

Try It Out: String Processing


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

METHOD if_oo_adt_classrun~main.

* Declarations
**********************************************************************
TYPES t_amount TYPE p LENGTH 8 DECIMALS 2.

DATA amount TYPE t_amount VALUE '3.30'.


DATA amount1 TYPE t_amount VALUE '1.20'.
DATA amount2 TYPE t_amount VALUE '2.10'.

DATA the_date TYPE d VALUE '19891109'.


DATA my_number TYPE p LENGTH 3 DECIMALS 2 VALUE '-273.15'.

DATA part1 TYPE string VALUE `Hello`.


DATA part2 TYPE string VALUE `World`.

* String Templates
**********************************************************************

" comment/uncomment the following lines for different examples


DATA(text) = |Hello World|.
* DATA(text) = |Total: { amount } EUR|.
* DATA(text) = |Total: { amount1 + amount2 } EUR|.

* Format Options

© Copyright. All rights reserved. 57


Unit 2: Basic Techniques and Concepts

**********************************************************************

"Date
* DATA(text) = |Raw Date: { the_date }|.
* DATA(text) = |ISO Date: { the_date Date = ISO }|.
* DATA(text) = |USER Date:{ the_date Date = USER }|.

"Number
* DATA(text) = |Raw Number { my_numer }|.
* DATA(text) = |User Format{ my_numer NUMBER = USER }|.
* DATA(text) = |Sign Right { my_number SIGN = RIGHT }|.
* DATA(text) = |Scientific { my_number STYLE = SCIENTIFIC }|.

* String expression (concatenation Operator)


**********************************************************************

* DATA(text) = part1 && part2.


* DATA(text) = part1 && | | && part2.
* DATA(text) = |{ amount1 } + { amount2 }| &&
* | = | &&
* |{ amount1 + amount2 }|.

* Output
**********************************************************************

out->write( text ).

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Play around with the source code to get familiar with the concepts.

● Uncomment different value assignments for inline-declared variable text to see


different result.

● Try your own assignements.

LESSON SUMMARY
You should now be able to:
● Perform arithmetic calculations
● Apply string processing

58 © Copyright. All rights reserved.


Unit 2
Lesson 4
Working with Simple Internal Tables

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Define simple internal tables
● Process data using simple internal tables

Defining a Simple Internal Table


Internal Tables
Internal tables are variable data objects in which you can store several values of identical type.
This type has to be specified in the declaration and is called the row type of the internal table.

Figure 44: Internal Tables

Each value occupies one row of the internal table. The number of rows is not restricted.
Theoretically, you can store any number of values in one internal table. Limitations only come
from technical boundaries like available memory or system configuration.
The initial value of an internal table is an empty table or, in other words, a table with 0 lines.
There are different techniques for filling an internal table. The example uses the APPEND
statement to add a new row at the end of the internal table and fill it with a value.

© Copyright. All rights reserved. 59


Unit 2: Basic Techniques and Concepts

Table Types

Figure 45: Table Types

There are also table types in the ABAP Dictionary. These table type are maintained with a
dedicated editor. They are called global table types because they are visible anywhere in the
system.

Processing Data with a Simple Internal Table

Figure 46: Filling an Internal Table with APPEND

One way to fill an internal table with data is the APPEND statement. With each APPEND
statement a new row is added to the internal table. This new row is then filled with the value of
the expression after keyword APPEND.
Note:
The type of the expression has to be compatible with the line type of the internal table. If it is
not identical, the system attempts an implicit type conversion.
Let's look at how you can process data with a simple internal table.

60 © Copyright. All rights reserved.


Lesson: Working with Simple Internal Tables

Animation
For more information on this topic please view the animation in the lesson
Working with Simple Internal Tables in your online course.

Figure 47: Emptying an Internal Table

The initial value of an internal table is an empty table, that is, an internal table with zero rows.
You already learned that with statement CLEAR you can reset an ABAP variable to its type-
specific initial value.
When you use CLEAR for an internal table, you delete all its content and set the number of
rows to zero.

Figure 48: Retrieve a Single Row From an Internal Table

There are various ways to retrieve data from an internal table. This example retrieves the
content of a single row using an internal table expression. In the table expression, the name of

© Copyright. All rights reserved. 61


Unit 2: Basic Techniques and Concepts

the internal table is followed immediately by a pair of square brackets. An integer expression
inside the brackets specifies the position of the row to be read.
Note:
Correct syntax requires at least one blank after the opening bracket and before the closing
bracket.

Figure 49: Reading from an Internal Table in a Loop

You can read all rows of an internal table and process them in turn by using a combination of
statements LOOP AT and ENDLOOP. LOOP AT and ENDLOOP always come in pairs, that is,
for each LOOP AT statement there has to be exactly one corresponding ENDLOOP statement.
Between LOOP AT and ENDLOOP, you can place any amount of ABAP code. The code you
place there is processed several times, once for each row of the internal table.

Note:
If the internal table is empty, the coding between LOOP AT and ENDLOOP is not
processed at all.

The data object listed after addition INTO is called the work area for the internal table. The
type of this data object must be identical to, or at least compatible with, the line type of the
internal table.
At the beginning of each round, the work area is filled with the data from the next table row.
In the example internal table numbers contains 3 rows. Therefore the coding between LOOP
AT and ENDLOOP is processed 3 times. During the first round, variable number contains 4711,
the value of the first row. This value is the written to the console. At the beginning of the
second round, the value in variable number is replaced with value 1234 from the second row,
and so on.

62 © Copyright. All rights reserved.


Lesson: Working with Simple Internal Tables

Figure 50: Inline Declaration of Work Area

When you implement a loop over an internal table, you can use an inline declaration after
addition INTO instead of declaring the work area explicitly with a DATA statement.
By doing so, you not only reduce the amount of code you have to type, you also ensure that
the type of work area fits the line type of the internal table, because the type of the inline
declared data object is derived from the context, which, in this case, is the internal table.

Try It Out: Simple Internal Tables


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Declarations
**********************************************************************

" Internal tables


DATA numbers TYPE TABLE OF i.

"Table type (local)


TYPES tt_strings TYPE TABLE OF string.
DATA texts1 TYPE tt_strings.

" Table type (global)


DATA texts2 TYPE string_table.

" work areas


DATA number TYPE i VALUE 1234.
DATA text TYPE string.

* Example 1: APPEND
**********************************************************************

APPEND 4711 TO numbers.


APPEND number TO numbers.
APPEND 2 * number TO numbers.

out->write( `-----------------` ).

© Copyright. All rights reserved. 63


Unit 2: Basic Techniques and Concepts

out->write( `Example 1: APPEND` ).


out->write( `-----------------` ).

out->write( numbers ).

* Example 2: CLEAR
**********************************************************************

CLEAR numbers.

out->write( `----------------` ).
out->write( `Example 2: CLEAR` ).
out->write( `----------------` ).

out->write( numbers ).

* Example 3: table expression


**********************************************************************
APPEND 4711 TO numbers.
APPEND number TO numbers.
APPEND 2 * number TO numbers.

out->write( `---------------------------` ).
out->write( `Example 3: Table Expression` ).
out->write( `---------------------------` ).

number = numbers[ 2 ] .

out->write( |Content of row 2: { number }| ).


"Direct use of expression in string template
out->write( |Content of row 1: { numbers[ 1 ] }| ).

* Example 4: LOOP ... ENDLOOP


**********************************************************************
out->write( `---------------------------` ).
out->write( `Example 4: LOOP ... ENDLOOP` ).
out->write( `---------------------------` ).

LOOP AT numbers INTO number.

out->write( |Row: { sy-tabix } Content { number }| ).

ENDLOOP.

* Example 5: Inline declaration in LOOP ... ENDLOOP


**********************************************************************
out->write( `-----------------------------` ).
out->write( `Example 5: Inline Declaration` ).
out->write( `-----------------------------` ).

LOOP AT numbers INTO DATA(number_inline).


out->write( |Row: { sy-tabix } Content { number_inline }| ).
ENDLOOP.

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Analyze the console output. Play around with the source code to get familiar with the
concepts.

LESSON SUMMARY
You should now be able to:
● Define simple internal tables

64 © Copyright. All rights reserved.


Lesson: Working with Simple Internal Tables

● Process data using simple internal tables

© Copyright. All rights reserved. 65


Unit 2: Basic Techniques and Concepts

66 © Copyright. All rights reserved.


Unit 2
Lesson 5
Using Control Structures in ABAP

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Implement conditional branching
● Implement Iterations
● Handle Exceptions

Implementing Conditional Branching

Figure 51: Branching with Freely Defined Conditions

A conditional branching is a control structure that allows you to make the execution of code
dependent on logical conditions.
The most common conditional branching consists of a pair of keywords IF and ENDIF. The
code block between IF and ENDIF is only executed, if the condition after IF is fulfilled.
You can add more code blocks by extending the IF … ENDIF structure with up to one keyword
ELSE and an arbitrary number of keywords ELSEIF. By adding keyword ELSE you ensure that
always exactly one of the code blocks is executed. If ELSE is missing it can happen that none
of the code blocks is executed.
The code block to be executed is determined as follows:
● First, the IF condition is evaluated. If it is fulfilled, the related code block is executed and
the program continues after ENDIF.

© Copyright. All rights reserved. 67


Unit 2: Basic Techniques and Concepts

● Only if the IF condition is not fulfilled, the condition after the first ELSEIF is evaluated. If it is
fulfilled, the related code block is executed and the program continues after ENDIF.
● This is done consecutively for all ELSEIF conditions. If none of the conditions is fulfilled and
the structure contains ELSE, the code block after ELSE is executed. Otherwise the none of
the code blocks is executed.

Hint:
As opposed to many other programming languages, ABAP requires a delimiter
(.) after each of the logical conditions and even after keyword ELSE.

Let's look at the different techniques of conditional branching.

Animation
For more information on this topic please view the animation in the lesson Using
Control Structures in ABAP in your online course.

Figure 52: Logical Conditions

Logical conditions are a combination of comparisons, logical operations, expressions and


functions that the runtime system evaluates to decide whether the condition is true or false.
The most common use-case for logical conditions is after keywords IF or ELSEIF in an IF ...
ENDIF. structure.
The first example is a simple comparison: The condition is true if the two data objects x and y
have the same value.
The second example is a bit more sophisticated: Either the value of x is greater than or equal
to y and less than twice the value of y or it is less than or equal to y and greater than twice the
value of y.
The third example makes use of arithmetic function abs( ) and logical expression BETWEEN
<expression1> AND <expression2> . The condition is true if the absolute value of x lies
between the absolute value of y and the absolute value of two times y.

68 © Copyright. All rights reserved.


Lesson: Using Control Structures in ABAP

For simple value comparisons you can use operators =, <>, >, <, >=, and <=. You can not only
compare the values of data objects, but the values of many other expressions, like the
arithmetic expression 2 * y in the example.

Note:
ABAP uses the same symbol (=) for value assignments and for value
comparisons. The distinction is made based on the position.

You can use operators AND and OR to combine logical expressions and operator NOT to
negate an expression. Without brackets, NOT binds stronger than AND and AND stronger
than OR.
ABAP knows some special logical expressions:
● <data object> IS INITIAL is true if <data object> contains its type-specific initial value
● <data object> IS NOT INITIAL is true if <data object> contains a value that is different from
the type-specific initial value
● <data object> BETWEEN <expression1> AND <expression2>

Some special ABAP functions are predicate functions. This means that they are logical
conditions themselves. Contains( ) is a function that compares character-like values and
line_exists( ) performs an existence check for a row in an internal table.

Figure 53: Branching with Equals Comparisons

A second technique for conditional branching is the CASE … WHEN .. ENDCASE control
structure.
Conditional branching with CASE .. ENDCASE is a special case of the more general branching
with IF … ENDIF. You can use CASE in situations where the branching depends on the value of
a single data object, which you consecutively compare to a set of possible values, using an
equals comparison each time.
In the example, the value of data object number is compared to values 1 and 2. If the value
equals 1, <code_block_1> is executed and if the value euqals 2, <code_blocl_2> is executed
instead. For any other value, the code block after WHEN OTHERS is executed.

© Copyright. All rights reserved. 69


Unit 2: Basic Techniques and Concepts

Any conditional branching with CASE … ENDCASE could be implemented with an IF … ENDIF
structure, as well. This is illustrated with the example on the right.

Hint:
You should use CASE … ENDCASE when dealing with the special case to increase
readability of your code.

Try It Out: Conditional Branching


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Declarations
**********************************************************************

CONSTANTS c_number TYPE i VALUE 0.


* CONSTANTS c_number TYPE i VALUE 1.
* CONSTANTS c_number TYPE i VALUE 2.
* CONSTANTS c_number TYPE i VALUE -1.
* CONSTANTS c_number TYPE i VALUE -2.

* Example 1: Simple IF ... ENDIF.


**********************************************************************

out->write( `--------------------------------` ).
out->write( `Example 1: Simple IF ... ENDIF.` ).
out->write( `-------------------------------` ).

IF c_number = 0.
out->write( `The value of C_NUMBER equals zero` ).
ELSE.
out->write( `The value of C_NUMBER is NOT zero` ).
ENDIF.

* Example 2: Optional Branches ELSEIF and ELSE


**********************************************************************

out->write( `--------------------------------------------` ).
out->write( `Example 2: Optional Branches ELSEIF and ELSE` ).
out->write( `--------------------------------------------` ).

IF c_number = 0.
out->write( `The value of C_NUMBER equals zero` ).
ELSEIF c_number > 0.
out->write( `The value of C_NUMBER is greater than zero` ).
ELSE.
out->write( `The value of C_NUMBER is less than zero` ).
ENDIF.

* Example 3: CASE ... ENDCASE


**********************************************************************

out->write( `---------------------------` ).
out->write( `Example 3: CASE ... ENDCASE` ).
out->write( `---------------------------` ).

70 © Copyright. All rights reserved.


Lesson: Using Control Structures in ABAP

CASE c_number.
WHEN 0.
out->write( `The value of C_NUMBER equals zero` ).
WHEN 1.
out->write( `The value of C_NUMBER equals one` ).
WHEN 2.
out->write( `The value of C_NUMBER equals two` ).
WHEN OTHERS.
out->write( `The value of C_NUMBER equals non of the above` ).
ENDCASE.

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Analyze the console output. Play around with the source code to get familiar with the
concepts; Uncomment different declarations of constant c_number with different values
to see, which branches of the code get executed.

Implementing Iterations

Figure 54: Iterations in ABAP

Iterations are control structures that define a block of code which is executed several times.
The simplest form of iteration consists of a code block surrounded by pair of statements DO
and ENDDO. Without further measures this establishes an endless loop which must be
avoided by one of the following possibilities:

Specified number of iterations


By extending the DO statement with an integer expression followed by keyword TIMES,
you can specify explicitly how often the code block is to be iterated. The integer
expression can be as simple as number literal, but also arithmetic calculations are an
option. If the value of the expression equals 0, the code block between DO and ENDDO is
not executed at all and the program immediately continues with the code after ENDDO.
Abort based on a logical condition
You can abort an iteration any time using the EXIT statement. The program then
continues with the code after ENDDO. Be aware that outside of iterations EXIT has a
different effect. There it terminates the processing of the current processing block, for
example the current method.

© Copyright. All rights reserved. 71


Unit 2: Basic Techniques and Concepts

Usually, EXIT is surrounded by IF and ENDIF to terminate the iteration depending on an


abort condition. Be aware that such iterations can turn into endless loops, if the abort
condition never gets true.
Of course it is possible to combine the two techniques, that is, explicitly specify the
number of iterations and then leave the iteration with EXIT. Thus the number of iterations
becomes a maximum number that might not be reached at runtime.
Based on an internal table
A third type of iteration is the LOOP … ENDLOOP structure that is used to consecutively
read the rows of an internal table. Here, the number of iterations is determined by the
number of rows in the internal table.

In the code block between DO and ENDDO, you can implement read-accesses to ABAP built-
in data object sy-index. This integer variable serves as an iteration counter, that is, the ABAP
runtime increases it by one at the beginning of each new iteration.

Note:
In contradiction to what you might be used to from other programming
languages, sy-index starts with value 1 during the first iteration.

ABAP built-in variable sy-tabix can fulfill a similar purpose for iterations with LOOP. But be
aware that strictly speaking sy-tabix is not really a counter but it identifies the position of the
table row that is processed in the current iteration. Later we will see the difference when not
all rows of an internal table are processed in a LOOP … ENDLOOP structure.

Try It Out: Iterations


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Declarations
**********************************************************************

CONSTANTS c_number TYPE i VALUE 3.


* CONSTANTS c_number TYPE i VALUE 5.
* CONSTANTS c_number TYPE i VALUE 10.

DATA number TYPE i.

* Example 1: DO ... ENDDO with TIMES


**********************************************************************

out->write( `----------------------------------` ).
out->write( `Example 1: DO ... ENDDO with TIMES` ).
out->write( `----------------------------------` ).

DO c_number TIMES.
out->write( `Hello World` ).
ENDDO.

* Example 2: DO ... ENDDO with Abort Condition


**********************************************************************

72 © Copyright. All rights reserved.


Lesson: Using Control Structures in ABAP

out->write( `-------------------------------` ).
out->write( `Example 2: With Abort Condition` ).
out->write( `-------------------------------` ).

number = c_number * c_number.

" count backwards from number to c_number.


DO.

out->write( |{ sy-index }: Value of number: { number }| ).


number = number - 1.

"abort condition
IF number <= c_number.
EXIT.
ENDIF.

ENDDO.

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Analyze the console output. Play around with the source code to get familiar with the
concepts; Uncomment different declarations of constant c_number to see how the
different values affect the result.

Handling Exceptions
Exceptions

Figure 55: Exceptions

In ABAP, an exception is an error situation during execution of an ABAP program. An


exception is raised by the code that detects the error situation.
Depending on who raises the exception, we distinguish between system exceptions and
application exceptions.
Without further measures exceptions result in runtime errors. A runtime error terminates the
program and is documented by default in a short dump.
You can avoid the runtime error if the exception in question is catchable. A catchable
exception can be treated in the program using statements TRY … CATCH … ENDTRY.

© Copyright. All rights reserved. 73


Unit 2: Basic Techniques and Concepts

All application exceptions and many system exceptions are catchable. Later in this course you
will learn how to raise application exceptions. At this point we will focus on the handling of
catchable system exceptions.
What are exceptions? Let's take a look.

Animation
For more information on this topic please view the animation in the lesson Using
Control Structures in ABAP in your online course.

Figure 56: Some Examples of Catchable System Exceptions

In the figure, Some Examples for Catchable System Exceptions, you can see some examples
of runtime errors:
● The first code example attempts a division with zero as the denominator. This is not
defined.
● The second code example wants to convert a character string into an integer number but
the character string cannot be interpreted as a number.
● The third code example tries to read the first row from an internal table. But the internal
table is initial and therefore no first row can be found.

When you execute the code examples on the left, the ABAP runtime raises catchable system
exceptions. These exceptions are not treated by the program yet, which leads to runtime
errors.
The screenshots on the right are snippets from the short dumps created by these runtime
errors. Beside a short text to describe the situation, you see the ID of the runtime error and
the ID of the uncaught exception.

74 © Copyright. All rights reserved.


Lesson: Using Control Structures in ABAP

Exception Handling

Figure 57: Exception Handling

To prevent a program from terminating because of a catchable exception, you have to


surround the code from where the exception originates with statements TRY and ENDTRY. By
doing so, the code becomes part of the TRY block of the TRY … ENDTRY structure.
Before the ENDTRY statement you have to add a CATCH statement followed by the ID of the
exception you want to handle. Optionally, you can add more than one CATCH statement to
handle several different exceptions. Each CATCH statement should be followed by code to
handle this exception. This code is called the CATCH block.
When program execution reaches the TRY statement, it continues with the code in the TRY
block. Three things can happen then:

1. If no exception is raised during the TRY block, the CATCH blocks are ignored. Execution
continues after the ENDTRY statement.

2. If an exception is raised during the TRY block, for which a matching CATCH exists,
execution of the TRY block is terminated and the CATCH block for this exception is
executed. Afterward, execution continues after the ENDTRY statement.

3. If an exception is raised during the TRY block for which no matching CATCH exists, the
program terminates with a runtime error.

Now that you have learned about exceptions, let's see how you can handle them.

Animation
For more information on this topic please view the animation in the lesson Using
Control Structures in ABAP in your online course.

© Copyright. All rights reserved. 75


Unit 2: Basic Techniques and Concepts

Figure 58: Example: Exception Handling

The example illustrates the handling of exception CX_SY_ZERODIVIDE which is raised if in a


division the denominator is zero.
The source code on the left and on the right is identical - except for the value that is assigned
to variable denominator. Red and green background colors are used to distinguish code that
is executed and code that is not executed.
On the left, the entire TRY block is executed and the CATCH block is ignored. On the right, the
TRY block is executed but only up to the code line, where the system raises the exception. The
rest of the TRY block is not executed. Instead, the CATCH block is executed.
The code after ENDTRY is executed in both cases. It is independent from the successful or
unsuccessful execution of the TRY block.

Try It Out: Exception Handling


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Declarations
**********************************************************************
DATA result TYPE i.

DATA numbers TYPE TABLE OF i.

* Preparation
**********************************************************************

APPEND 123 TO numbers.

* Example 1: Conversion Error (no Number)


**********************************************************************

CONSTANTS c_text TYPE string VALUE 'ABC'.


* CONSTANTS c_text TYPE string VALUE '123'.

out->write( `---------------------------` ).

76 © Copyright. All rights reserved.


Lesson: Using Control Structures in ABAP

out->write( `Example 1: Conversion Error` ).


out->write( `---------------------------` ).

TRY.
result = c_text.
out->write( |Converted content is { result }| ).
CATCH cx_sy_conversion_no_number.
out->write( |Error: { c_text } is not a number!| ).
ENDTRY.

* Example 2: Division by Zero


**********************************************************************

CONSTANTS c_number TYPE i VALUE 0.


* CONSTANTS c_number TYPE i VALUE 7.

out->write( `---------------------------` ).
out->write( `Example 2: Division by Zero` ).
out->write( `---------------------------` ).

TRY.
result = 100 / c_number.
out->write( |100 divided by { c_number } equals { result }| ).
CATCH cx_sy_zerodivide.
out->write( `Error: Division by zero is not defined!` ).
ENDTRY.

* Example 3: Itab Error (Line Not Found)


**********************************************************************

CONSTANTS c_index TYPE i VALUE 2.


* CONSTANTS c_index TYPE i VALUE 1.

out->write( `-------------------------` ).
out->write( `Example 3: Line Not Found` ).
out->write( `-------------------------` ).

TRY.
result = numbers[ c_index ].
out->write( |Content of row { c_index } equals { result }| ).
CATCH cx_sy_itab_line_not_found.
out->write( `Error: Itab has less than { c_index } rows!` ).
ENDTRY.

* Example 4: Combination of Different Exceptions


**********************************************************************
* CONSTANTS c_char TYPE c LENGTH 1 VALUE 'X'.
* CONSTANTS c_char TYPE c length 1 value '0'.
CONSTANTS c_char TYPE c LENGTH 1 VALUE '1'.
* CONSTANTS c_char TYPE c length 1 value '2'.

out->write( `----------------------` ).
out->write( `Example 4: Combination` ).
out->write( `----------------------` ).

TRY.
result = numbers[ 2 / c_char ].
out->write( |Result: { result } | ).
CATCH cx_sy_zerodivide.
out->write( `Error: Division by zero is not defined` ).
CATCH cx_sy_conversion_no_number.
out->write( |Error: { c_char } is not a number! | ).
CATCH cx_sy_itab_line_not_found.

© Copyright. All rights reserved. 77


Unit 2: Basic Techniques and Concepts

out->write( |Error: Itab contains less than { 2 / c_char }


rows| ).
ENDTRY.

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Analyze the console output. Play around with the source code to get familiar with the
concept:

● Comment the exception handling to make the system raise a runtime error.

● Change the values of constants c_number, c_text, c_index, and c_charin a way
that no exceptions are raised.

LESSON SUMMARY
You should now be able to:
● Implement conditional branching
● Implement Iterations
● Handle Exceptions

78 © Copyright. All rights reserved.


Unit 2
Lesson 6
Debugging an ABAP Program

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Enter debugging mode
● Control the execution of code
● Analyze the content of data objects

Entering Debugging Mode

Figure 59: The Need For Debugging

There is no way around the fact that errors occur in programs. However, they manifest
themselves in different ways. When a user starts a faulty application, it may crash, something
unexpected may happen, or nothing at all may happen. From the user's point of view, at user
interface level, it is impossible to say just how and why this error occurred.
As a developer, you now need to examine the program more closely - line-by-line in fact - to
establish just what statements and combinations of values in the different program variables
caused the error. This is where the Debugger comes in.
Watch this video to understand the need for debugging.

© Copyright. All rights reserved. 79


Unit 2: Basic Techniques and Concepts

Video: The Need for Debugging


For more information on The Need for Debugging, please view the video in the
lesson Debugging an ABAP Program in your online course.

Starting the Debugger

Figure 60: Starting the Debugger

To debug an ABAP program, you set a breakpoint then run the program normally. When the
program reaches the breakpoint, the system interrupts it and opens the ABAP Debug
perspective in ADT. You can then execute each subsequent statement individually to see what
effect it has on the program. You can also inspect the contents of all of the variables in the
program to see if any of the values are unexpected.
To set or remove a breakpoint, right-click the left margin of the editor and choose Toggle
Breakpoint. As an alternative you can double-click the left margin. Note that the program has
to be activated before you can set breakpoints.
Breakpoints are user-specific and are persistent - they remain active even after you have
logged off from ADT and back on again. To prevent the debugger from starting at a breakpoint
you must either delete the breakpoint (using the Toggle Breakpoint function) or deactivate it
using the corresponding function in the context menu.

Note:
Depending on your personalization settings, ADT will ask for confirmation, first,
before automatically opening the debug perspective.

80 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

The Debug Perspective in ADT

Figure 61: The Debug Perspective in ADT

When you debug an ABAP program using ABAP Development Tools, you use the Debug
perspective. This is a customized version of the standard Eclipse Debug perspective, and it
contains views and functions that are particularly important for debugging.
Some important elements of the debugger perspective ar as follows:

Source Code View


The Source Code view is the central part of the debugger perspective. It displays the
source code and highlights the current position in the program.
Variables View
The Variables view is also very important. You use this view to display the current values
of variables.
Breakpoints View
The Breakpoints view is displayed next to the Variables view (not selected in the figure
above). You use this view to display, delete or create breakpoints. Breakpoints are points
in the program at which normal processing is interrupted and the system shows you the
Debugger so that you can analyze the state of the program at exactly that moment.
Navigation Functions
While debugging a program, you use the navigation functions to control the execution of
the code.
Debug View
The Debug view on the upper left shows the debugging session and the call hierarchy.
You will need this later when you debug calls of modularization units, for example,
methods.
Perspective Selector
You can switch back to the ABAP perspective with the Perspective Selector buttons in the
right upper corner.

© Copyright. All rights reserved. 81


Unit 2: Basic Techniques and Concepts

Hint:
Because many important editor tools are missing from the Debugger
perspective it is recommended to switch back to the ABAP perspective
once you finished debugging.

Animation
For more information on this topic please view the animation in the lesson
Debugging an ABAP Program in your online course.

Controlling the Execution Of Code


Some Navigation Functions

Once you started debugging, use the navigation functions to control the execution of the
code.
Some important navigation functions are as follows:

Step Into (F5)


Choose Step Into or press F5 to execute a single step. Use this function for a step-by-
step analysis. If, for example, you want to see which code block of a control structure is
actually executed.
Resume (F8)
Choose Resume or press F8 to execute the program up to the next breakpoint. If the
debugger does not hit any more breakpoints, the program is executed to the end and the
debugging session terminates.
Run to Line (Shift+F8)
Choose Run to Line or press Shift+F8 to execute the program up to the current cursor
position. Clicking on a code line and choosing this function is a convenient alternative to
setting a breakpoint, choosing Resume and removing the breakpoint again.
Jump to Line (Shift+F12)
Choose Jump to Line or press Shift+F12 to skip some lines of code or to jump
backwards to some already executed code. This function can be helpful to simulate what
would happen if a certain piece of code was removed or to repeat debugging a bit of code
you missed analysis the first time. Keep in mind that this is actually jumping, not
executing coding. When you jump backwards, changes to data objects are not reverted!
Terminate
Choose Terminate if you are done with debugging and you do not want to execute the
remaining program. The debug session terminates immediately.

Some important navigation functions are shown here.

82 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

Animation
For more information on this topic please view the animation in the lesson
Debugging an ABAP Program in your online course.

Special Breakpoints

Figure 62: Creating Special Breakpoints

You learned that you can create and manage breakpoints by clicking on the left margin of the
ABAP editor view. This also works with the ABAP editor view in the Debug perspective.
In addition, you can switch to the Breakpoints view and manage your breakpoints there.
In the Breakpoints view you can also create special breakpoints:

Statement Breakpoint
A statement breakpoint is not attached to a specific line of code but to a specific ABAP
statement. A statement breakpoint on statement CLEAR, for example, causes the
program to stop in the debugger whenever a CLEAR statement is executed - no matter
where this statement is located.
To create a statement breakpoint, open the dropdown list from the toolbar of the
Breakpoints view and choose Add Statement Breakpoint … .
Exception Breakpoint
An exception breakpoint is attached to a specific exception. It causes the program to
stop in the debugger whenever this particular exception is raised - no matter if this
exception is handled by the program or causes a runtime error. To create an exception
breakpoint, open the dropdown list from the toolbar of the Breakpoints view and choose
Add Exception Breakpoint … .
Conditional Breakpoints
You turn a breakpoint into a conditional breakpoint by adding a condition. If program
execution hits a conditional breakpoint, the program only stops in the debugger, if the
condition is fulfilled. If, for example, a breakpoint is located between DO and ENDDO it will
cause the program to stop in the debugger in every iteration. But if you add a condition

© Copyright. All rights reserved. 83


Unit 2: Basic Techniques and Concepts

sy-index > 20 the debugger will ignore this breakpoint during the first 20 iterations and
only stop in the following iterations.
To add a condition to a breakpoint, choose it in the list of breakpoints and enter the
condition in field Condition. Press Enter to save the breakpoint with the condition.

Watchpoints

Figure 63: Watchpoints

If an unexpected value of a variable is causing you problems, you can track its value during the
course of the program using a watchpoint.
A simple watchpoint on a variable causes the program to stop in the debugger whenever the
value of this variable changes. By adding a condition, you can achieve that the program does
not stop at every value change of the variable but only in those cases where also the condition
is the fulfilled.
To set a watchpoint on a variable, double-click the variable in the source-code display, then
right-click it and choose Set Watchpoint. This creates a watchpoint on this variable, which
you can then see in the Breakpoints view.
To add a condition to a watchpoint, choose it in the list of breakpoints and enter the condition
in field Condition. Press Enter to save the watchpoint with the condition.
Watch this video to see how.

Video: Watchpoints
For more information on Watchpoints, please view the video in the lesson
Debugging an ABAP Program in your online course.

84 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

Analyzing The Contents Of Data Objects


Display Content of Data Objects

Figure 64: Display content of data objects

One way to analyze the content of data objects in the debugger is the mouse-over
functionality of the ABAP Editor. While in debugging mode, place the cursor on the name of a
data object and wait a moment. A dialog box opens with the content of the data object.
Another way to analyze the content of data objects in the debugger is the Variables view. This
view displays a list of data objects and their current values. The main list, the so-called top-
level variables, contains some built-in data objects, by default. In the example, these are SY-
SUBRC and ME. Expand node Locals to see a list of all variable data objects defined in the
current processing block.
There are three ways to add data objects to the main list on the Variables view:
● In the editor, double-click on the name of a data object
● In the variables list, left-click on placeholder <Enter variable> and enter the name of the
data object
● Right-click on a variable in Locals node and choose Show as Top Level Variable

Hint:
To remove a data object from the list, right-click on it and choose Remove.

Watch this video to learn how to display the content of data objects in the debugger.

Video: Display Content of Data Objects


For more information on Display Content of Data Objects, please view the video
in the lesson Debugging an ABAP Program in your online course.

© Copyright. All rights reserved. 85


Unit 2: Basic Techniques and Concepts

Display Content of Internal Tables

Figure 65: Display content of internal tables

For internal tables, the Variables view displays an overview with the number of rows and the
number of columns. Expand the hierarchy below the name of the internal table to see the
content of selected rows. Double-click the name of the internal table to analyze it in the ABAP
Internal Table view.
The ABAP Internal Table view is a debugger tool to analyze the content of internal tables. In
the default configuration of the debugger perspective the ABAP Internal Table view is one of
the views below the source code. You can filter the table content by entering a filter pattern
and pressing Enter.
Watch this video to learn how to display the content of internal tables.

Video: Display Content of Internal Tables


For more information on Display Content of Internal Tables, please view the
video in the lesson Debugging an ABAP Program in your online course.

86 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

Changing the Values of Variable

Figure 66: Changing the values of variables

For simple variables, locate the variable in the Variables view, right-click on it and choose
Change Value ….
To change the content of an internal table, we have to distinguish between changing the value
of an existing row and adding or deleting of a rows.
As shown in the figure, the following functions are available when you right-click in the ABAP
internal table view:

Change Value …
Choose Change Value …. to change the content of an existing row.
Insert Row …
Choose Insert Row …. to add a new row. You can decide whether you want to append the
new row or insert it at the chose position.
Delete Selected Rows …
Choose Delete Selected Rows … to remove the rows you selected before you right-
clicked. To select a row, left-click it. To select more than one row, hold down the Ctrl key
or the Shift key when you left-click additional rows.
Delete Rows …
Choose Delete Rows …to remove a larger range of rows, or even all rows. You are asked
for the number of the start row and the end row you want to delete.

© Copyright. All rights reserved. 87


Unit 2: Basic Techniques and Concepts

88 © Copyright. All rights reserved.


Unit 2
Exercise 3
Debug an ABAP Program

In this exercise, you analyze a program using the ABAP debugger.

Task 1: Preparation
Before you can start debugging you have to create the program and copy the source code.

1. Create a new global class ZCL_##_DEBUG, where ## is your group number. Ensure that
the class implements the interface IF_OO_ADT_CLASSRUN.

2. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

* Declarations
**********************************************************************
" Types
TYPES t_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES t_percentage TYPE p LENGTH 2 DECIMALS 1.

" Input for the calculation


CONSTANTS loan_total TYPE t_amount VALUE '50000.00'.
CONSTANTS interest_rate TYPE t_percentage VALUE '2.0'.
CONSTANTS payment_month TYPE t_amount VALUE '1000.00'.
CONSTANTS spec_repay_year TYPE t_amount VALUE '10000.00'. "
Extra payment per year
CONSTANTS spec_repay_mode TYPE c LENGTH 1 VALUE 'Q'.
"'A' Annual, 'H' every half year, 'Q' 'every Quarter

" Output
DATA repayment_plan TYPE TABLE OF string.

" Helper Variables


DATA loan_remaining TYPE t_amount.
DATA interest_month TYPE t_amount.
DATA repayment_month TYPE t_amount.
DATA interest_total TYPE t_amount.
DATA special_repayment TYPE t_amount.

DATA months_counter TYPE i.


DATA months_btw_spec_pay TYPE i.

* Processing
**********************************************************************

" Initializations
loan_remaining = loan_total.

CASE spec_repay_mode.
WHEN 'A'.
months_btw_spec_pay = 12.
special_repayment = spec_repay_year.

© Copyright. All rights reserved. 89


Unit 2: Basic Techniques and Concepts

WHEN 'H'.
months_btw_spec_pay = 6.
special_repayment = spec_repay_year / 2.
WHEN 'Q'.
months_btw_spec_pay = 3.
special_repayment = spec_repay_year / 4.
WHEN OTHERS.
out->write( 'Invalid extra payment mode' ).
EXIT.
ENDCASE.

" Calculations
DO.

IF loan_remaining <= 0.
EXIT.
ENDIF.

DO months_btw_spec_pay TIMES.

months_counter = months_counter + 1.

" calculate interest and back payment for current month


interest_month = loan_remaining * ( interest_rate /
100 ) / 12 .
repayment_month = payment_month - interest_month.

" add monthly interest to total interest


interest_total = interest_total + interest_month.

" deduct repayment


loan_remaining = loan_remaining - repayment_month.

" add payment to repayment plan


APPEND |Month { months_counter } - Interest:
{ interest_month } Remaining loan: { loan_remaining } |
TO repayment_plan.

IF loan_remaining < 0.
EXIT.
ENDIF.
ENDDO.

IF loan_remaining < 0.
EXIT.
ENDIF.

" deduct the special repayment (n times a year, spec_repay_year


over the year )
loan_remaining = loan_remaining - special_repayment.

"add special repayment to repayment plan


APPEND |Special repayment of { special_repayment }! Remaining
loan { loan_remaining } |
TO repayment_plan.
ENDDO.

* Output
**********************************************************************

out->write( |Starting value of loan: { loan_total }| ).


out->write( |Monthly payment: { payment_month }| ).
out->write( |Special repayment { special_repayment } every

90 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

{ months_btw_spec_pay } months. | ).

out->write( |-----------------------
Result-----------------------| ).
out->write( |Total repayment after { months_counter DIV 12 } years
and { months_counter MOD 12 } months. | ).
out->write( |Total interest paid: { interest_total } | ).

"Repayment Plan
out->write(
name = `Repayment Plan:`
data = repayment_plan
).

3. Activate and test the class.

4. Check the output in the Console view.

Task 2: Analyze the Starting Values


Enter the debugger at the first executable statement in method
if_oo_adt_classrun~main( ) and analyze the values of some variable and constant data
objects.

1. Set a breakpoint at the first statement that does not define a type or declare a data object.

Hint:
TYPES defines a data type, CONSTANTS declares a constant data object,
DATA declares a variable data object.

2. Run the class as a console app and enter the debugger.

3. Display the value of data object loan_remaining and loan_total in the Variables view.

Task 3: Control Program Execution


Set break points and watch points. Execute single steps or resume execution until the next
break point or watch point is reached. Supervise the value changes of the data objects.

1. Execute a single step to debug the value assignment in the current line.

2. Display the content of data object spec_repay_mode. Then execute another single step
to see which WHEN branch of the CASE - control structure is executed.

3. Set a watch point for variable loan_remaining and resume program execution. Where
does the program execution stop again?

4. Display the content of data object repayment_plan. Then execute another single step to
see how it is filled with the APPEND statement.

Note:
Because repayment_plan is an internal table, it not only displays in the
Variables view but also in the ABAP Internal Table (Debugger) view below the
editor.

© Copyright. All rights reserved. 91


Unit 2: Basic Techniques and Concepts

5. Inspect the string template in the APPEND statement and relate it to the resulting first row
in internal table repayment_plan. Display the content of the data objects that appear in
the embedded expressions.

6. Resume program execution for a few times. Whenever execution reaches one of the watch
points, analyze the value of loan_remaining and new rows are added to
repayment_plan.

7. After a while, set a statement break point for all EXIT statements and delete the two watch
points.

8. Resume program execution until you reach the first EXIT statement. Deactivate the
statement breakpoint for the EXIT statement. Then execute single steps until you reach
the output part of the program.

9. Open the Console view. Execute the remaining program and pursue the output on the
console view.

Note:
Do not press F5 to debug the output. Use F6 instead.

Note:
As you will learn later in the course out->write( ... ) is not an ABAP
statement but a reusable code block that consists of many ABAP statements.
By pressing F5 you Step Into this code to analyze it in detail. With F6 you Step
Over the code block, treating it like a single statement.

10. When the application is terminated, do not forget to switch back to the ABAP perspective

92 © Copyright. All rights reserved.


Unit 2
Solution 3
Debug an ABAP Program

In this exercise, you analyze a program using the ABAP debugger.

Task 1: Preparation
Before you can start debugging you have to create the program and copy the source code.

1. Create a new global class ZCL_##_DEBUG, where ## is your group number. Ensure that
the class implements the interface IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_CDS, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

2. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

* Declarations
**********************************************************************
" Types
TYPES t_amount TYPE p LENGTH 8 DECIMALS 2.
TYPES t_percentage TYPE p LENGTH 2 DECIMALS 1.

" Input for the calculation


CONSTANTS loan_total TYPE t_amount VALUE '50000.00'.
CONSTANTS interest_rate TYPE t_percentage VALUE '2.0'.
CONSTANTS payment_month TYPE t_amount VALUE '1000.00'.
CONSTANTS spec_repay_year TYPE t_amount VALUE '10000.00'. "
Extra payment per year
CONSTANTS spec_repay_mode TYPE c LENGTH 1 VALUE 'Q'.
"'A' Annual, 'H' every half year, 'Q' 'every Quarter

" Output
DATA repayment_plan TYPE TABLE OF string.

" Helper Variables


DATA loan_remaining TYPE t_amount.
DATA interest_month TYPE t_amount.
DATA repayment_month TYPE t_amount.
DATA interest_total TYPE t_amount.
DATA special_repayment TYPE t_amount.

© Copyright. All rights reserved. 93


Unit 2: Basic Techniques and Concepts

DATA months_counter TYPE i.


DATA months_btw_spec_pay TYPE i.

* Processing
**********************************************************************

" Initializations
loan_remaining = loan_total.

CASE spec_repay_mode.
WHEN 'A'.
months_btw_spec_pay = 12.
special_repayment = spec_repay_year.
WHEN 'H'.
months_btw_spec_pay = 6.
special_repayment = spec_repay_year / 2.
WHEN 'Q'.
months_btw_spec_pay = 3.
special_repayment = spec_repay_year / 4.
WHEN OTHERS.
out->write( 'Invalid extra payment mode' ).
EXIT.
ENDCASE.

" Calculations
DO.

IF loan_remaining <= 0.
EXIT.
ENDIF.

DO months_btw_spec_pay TIMES.

months_counter = months_counter + 1.

" calculate interest and back payment for current month


interest_month = loan_remaining * ( interest_rate /
100 ) / 12 .
repayment_month = payment_month - interest_month.

" add monthly interest to total interest


interest_total = interest_total + interest_month.

" deduct repayment


loan_remaining = loan_remaining - repayment_month.

" add payment to repayment plan


APPEND |Month { months_counter } - Interest:
{ interest_month } Remaining loan: { loan_remaining } |
TO repayment_plan.

IF loan_remaining < 0.
EXIT.
ENDIF.
ENDDO.

IF loan_remaining < 0.
EXIT.
ENDIF.

" deduct the special repayment (n times a year, spec_repay_year


over the year )

94 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

loan_remaining = loan_remaining - special_repayment.

"add special repayment to repayment plan


APPEND |Special repayment of { special_repayment }! Remaining
loan { loan_remaining } |
TO repayment_plan.
ENDDO.

* Output
**********************************************************************

out->write( |Starting value of loan: { loan_total }| ).


out->write( |Monthly payment: { payment_month }| ).
out->write( |Special repayment { special_repayment } every
{ months_btw_spec_pay } months. | ).

out->write( |-----------------------
Result-----------------------| ).
out->write( |Total repayment after { months_counter DIV 12 } years
and { months_counter MOD 12 } months. | ).
out->write( |Total interest paid: { interest_total } | ).

"Repayment Plan
out->write(
name = `Repayment Plan:`
data = repayment_plan
).

a) On the Global Class tab, insert the source code between METHOD
if_oo_adt_classrun~main. and ENDMETHOD..

3. Activate and test the class.


a) Press Ctrl + F3 to activate the class.

b) Press F9 to run the class.

4. Check the output in the Console view.


a) Check the Console view that should have opened as a new tab below the editor view.

b) If the Console view is not visible, open it by choosing Window → Show view → Other.
Double-click Console in the hit list.

Task 2: Analyze the Starting Values


Enter the debugger at the first executable statement in method
if_oo_adt_classrun~main( ) and analyze the values of some variable and constant data
objects.

1. Set a breakpoint at the first statement that does not define a type or declare a data object.

Hint:
TYPES defines a data type, CONSTANTS declares a constant data object,
DATA declares a variable data object.

a) Double-click the left-hand margin of the editor next to the line loan_remaining =
loan_total.to set a break point.

2. Run the class as a console app and enter the debugger.

© Copyright. All rights reserved. 95


Unit 2: Basic Techniques and Concepts

a) Press F9 to run the class.

b) If you are asked whether you want to switch to the Debug perspective, mark
Remember my decision and choose OK.

3. Display the value of data object loan_remaining and loan_total in the Variables view.
a) In the current code line (the one with a green background) double-click
loan_remaining.

b) In the same code line, double-click loan_total.

Task 3: Control Program Execution


Set break points and watch points. Execute single steps or resume execution until the next
break point or watch point is reached. Supervise the value changes of the data objects.

1. Execute a single step to debug the value assignment in the current line.
a) In the toolbar, choose Step Into (F5) or press F5.

b) Check that the the value of loan_remaining changed from 0..00to 5000.00.

2. Display the content of data object spec_repay_mode. Then execute another single step
to see which WHEN branch of the CASE - control structure is executed.
a) In the next code line, double-click spec_repay_mode.

b) Press F5 to see that the program jumps to code line WHEN 'Q'..

3. Set a watch point for variable loan_remaining and resume program execution. Where
does the program execution stop again?
a) In the Variables view, right-click on LOAN_REMAINING and choose Set Watchpoint.

b) In the toolbar, choose Resume (F8) or press F8.

c) Program execution stops immediately after code line loan_remaining =


loan_remaining - repayment_month., also to be precise, in the next code line
with executable code.

4. Display the content of data object repayment_plan. Then execute another single step to
see how it is filled with the APPEND statement.

Note:
Because repayment_plan is an internal table, it not only displays in the
Variables view but also in the ABAP Internal Table (Debugger) view below the
editor.

a) Double-click on repayment_plan at the end of the APPEND statement.

b) Press F5 to see how repayment_plan is filled with a first row.

5. Inspect the string template in the APPEND statement and relate it to the resulting first row
in internal table repayment_plan. Display the content of the data objects that appear in
the embedded expressions.
a) Double-click the data objects that appear between the curly brackets to display their
contents.

96 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

6. Resume program execution for a few times. Whenever execution reaches one of the watch
points, analyze the value of loan_remaining and new rows are added to
repayment_plan.
a) Press F8 to resume program execution.

b) Analyze the data objects in the Variables view and the ABAP Internal Table (Debugger)
view.

7. After a while, set a statement break point for all EXIT statements and delete the two watch
points.
a) Navigate to the Breakpoints view.

Hint:
You find the Breakpoints view next to the Variables view.

b) In the toolbar of the Breakpoints view, expand the dropdown button on the very left
and choose Add Statement Breakpoint ....

c) On the dialog window that appears, enter EXIT as search string, click on the value EXIT
in the hitlist, and choose OK.

d) In the Breakpoints view, right-click the watchpoint LOAN_REMAINING and choose


Remove.

e) In the Breakpoints view, right-click the watchpoint REPAYMENT_PLAN and choose


Remove.

8. Resume program execution until you reach the first EXIT statement. Deactivate the
statement breakpoint for the EXIT statement. Then execute single steps until you reach
the output part of the program.
a) Press F8 to resume program execution.

b) Switch to the Breakpoints view and deselect the line that says EXIT [Statement].

c) Press F5 until you reach the first code line that starts with out->write(.

9. Open the Console view. Execute the remaining program and pursue the output on the
console view.

Note:
Do not press F5 to debug the output. Use F6 instead.

Note:
As you will learn later in the course out->write( ... ) is not an ABAP
statement but a reusable code block that consists of many ABAP statements.
By pressing F5 you Step Into this code to analyze it in detail. With F6 you Step
Over the code block, treating it like a single statement.

a) Press F6 several times until you reach the end of the application.

© Copyright. All rights reserved. 97


Unit 2: Basic Techniques and Concepts

b) Analyze the addition output on the Console view and compare it to the string template
in the previous code line.

10. When the application is terminated, do not forget to switch back to the ABAP perspective
a) Choose ABAP on the very right of the Eclipse toolbar.

98 © Copyright. All rights reserved.


Lesson: Debugging an ABAP Program

LESSON SUMMARY
You should now be able to:
● Enter debugging mode
● Control the execution of code
● Analyze the content of data objects

© Copyright. All rights reserved. 99


Unit 2: Basic Techniques and Concepts

100 © Copyright. All rights reserved.


Unit 2

Learning Assessment

1. Which of the following can you use to denote a comment in ABAP?


Choose the correct answers.

X A // at the beginning of a line

X B * at the beginning of a line

X C -- anywhere in the line

X D " anywhere in the line

2. Which of the following predefined ABAP types are complete?


Choose the correct answers.

X A C

X B D

X C P

X D I

3. You declare a variable as follows: DATA var TYPE I VALUE 100. Subsequently, you use the
statement CLEAR var. What is the value of var after the CLEAR statement?
Choose the correct answer.

X A 0

X B 100

4. The result of the expression result = var MOD 2. is 1. What does this tell you about the
value of variable var?
Choose the correct answer.

X A var is an even number.

X B var is an odd number.

© Copyright. All rights reserved. 101


Unit 2: Learning Assessment

5. You want to concatenate two strings. Which is the correct operator?


Choose the correct answer.

X A +

X B &

X C ++

X D &&

6. When you declare an internal table, you must specify how many rows it may contain.
Determine whether this statement is true or false.

X True

X False

7. What is the work area of an internal table?


Choose the correct answer.

X A The first row of the internal table

X B The current row of the internal table

X C A variable with the same type as the row type of the internal table

8. The IF condition IF a > 10. is followed by the ELSEIF condition ELSEIF a = 25.The variable a
has the value 25. Which code branch or branches are executed?
Choose the correct answer.

X A The branch introduced by IF a > 10.

X B The branch introduced by ELSEIF a = 25.

X C Both branches.

9. How can you exit a loop in ABAP?


Choose the correct answers.

X A After a certain number of repetitions

X B After a certain length of time

X C When a particular condition is met

102 © Copyright. All rights reserved.


Unit 2: Learning Assessment

10. Which of the following statements about exceptions are true?


Choose the correct answers.

X A All uncaught exceptions lead to runtime errors.

X B All execptions are catchable.

X C Some exceptions are catchable, others are uncatchable.

X D A TRY...ENDTRY block must contain at least two CATCH statements.

11. What information do you see when you position the mouse pointer over a variable in the
debugger?
Choose the correct answer.

X A The data type of the variable

X B The current contents of the variable

X C The current memory consumption of the variable

12. When you press F8 (Continue) in the debugger, where could the program processing next
stop?
Choose the correct answers.

X A In the next line

X B At a subsequent breakpoint

X C At the end of the program

X D At the next ENDMETHOD statement.

© Copyright. All rights reserved. 103


Unit 2: Learning Assessment

104 © Copyright. All rights reserved.


UNIT 3 Local Classes

Lesson 1
Defining a local class 106
Exercise 4: Define a Local Class 111

Lesson 2
Creating Instances Of A Class 115
Exercise 5: Create and Manage Instances 121

Lesson 3
Defining And Calling Methods 128
Exercise 6: Define and Call Methods 139

Lesson 4
Using Encapsulation To Ensure Consistency 150
Exercise 7: Use Private Attributes and Constructors 157

UNIT OBJECTIVES

● Define a local class inside a global class


● Create Instances of an ABAP Class
● Define and call methods
● Explain Encapsulation
● Define and Use Constructors

© Copyright. All rights reserved. 105


Unit 3
Lesson 1
Defining a local class

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Define a local class inside a global class

Define a Local Class


Local And Global Classes
Classes in ABAP can be either local or global.

Figure 67: Local And Global Classes

Global classes are stored centrally and are contained in their own repository object called a
class pool. A global class can serve as main program. Global classes can also contain logic to
be reused by other ABAP programs, including other global classes.
Local classes are defined as part of an ABAP program, for example a global class. You can use
them only in the program or class in which they are defined. Local classes are useful for
entities or functions that you only need in a single program.
The ABAP syntax of both local and global classes is almost identical. In this course, you will be
working with local classes in your global class. The global class with method
if_oo_adt_classrun~main will only serve as a kind of main program.

Local Classes in Global Classes


As shown in the figure below, when you open a global class in ADT, the focus is on tab Global
Class, first. Here you find the source code of the global class itself. To see or enter the source
code of local classes, you have to navigate to tab Local Types.

106 © Copyright. All rights reserved.


Lesson: Defining a local class

Figure 68: Local Classes in Global Classes

ADT provides a source code template for local class. To use this template proceed as follows:

1. In the ABAP editor, type lcl and press Ctrl + Space.

2. From the list that displays choose lcl - Local class and press Enter.

3. Adjust the name of the new local class.

For the classes in this course you have to remove the create private addition from the CLASS
… DEFINITION statement.

Declare Attributes
Source Code of a Class in ABAP

Figure 69: Source Code of a Class in ABAP

In ABAP. the source code of a class has two parts - the definition and the implementation. The
definition part of a class is subdivided into up to three sections, called the visibility sections of
the class.

© Copyright. All rights reserved. 107


Unit 3: Local Classes

Animation
For more information on this topic please view the animation in the lesson
Defining a local class in your online course.

Definition
The definition part of a class contains the definition and declaration of all of the elements
in the class, that is, the types, the constants, the attributes, and the methods. It begins
with CLASS <class_name> DEFINITION. and ends with ENDCLASS.
Implementation
The implementation part of a class contains the executable code of the class, namely the
implementation of its methods. It begins with CLASS <class_name> IMPLEMENTATION.
and ends with ENDCLASS. The implementation part of a class is optional. It becomes
mandatory as soon as the class definition contains executable methods.
Visibility sections
Each visibility section of a class starts with one of the statements PUBLIC SECTION,
PROTECTED SECTION, PRIVATE SECTION and ends implicitly when the next section
begins. The last section ends with statement ENDCLASS. All declarations of a class have
to be inside one of the sections. In other words: No declarations are allowed between the
beginning of the class definition and the beginning of the first section.
The section in which a declaration is located defines the visibility of the declared element
of the class.
The three visibility sections of a class are optional; if you do not need a particular section,
you do not have to declare it. But if a class definition consists of more than one section,
they must follow the order PUBLIC SECTION - PROTECTED SECTION - PRIVATE
SECTION.

Definition Part of a Class

Figure 70: Definition Part of a Class

The figure shows the different kinds of components you can define in a class. You can define
any of these components in any visibility section of the class.

108 © Copyright. All rights reserved.


Lesson: Defining a local class

Animation
For more information on this topic please view the animation in the lesson
Defining a local class in your online course.

TYPES
The TYPES statement allows you to define types within your class. You do this in exactly
the same way as you would outside a class. If types are public, a program that uses the
class can use the type (or types) to declare ist own variables.
DATA and CLASS-DATA
You use DATA and CLASS-DATA to declare the attributes of the class. DATA declares an
instance attribute, while CLASS-DATA declares a static attribute.
CONSTANTS
Classes may also contain constants which are declared with CONSTANTS. Constants
and types are static components of the class.
METHODS and CLASS-METHODS
You use METHODS and CLASS-METHODS to define the methods of a class. METHODS
defines an instance method, while CLASS-METHODS defines a static method. The name
of the method is followed by the method's signature; that is, the set of values that the
method exchanges with its caller and the exceptions that may arise during the method.

Example: Attributes of the Flight Connection Class

Figure 71: Example: Attributes of the Flight Connection Class

Let us start implementing our UML model in ABAP, and take the attributes of the connection
class to begin with. To declare an attribute, use the DATA statement within the appropriate
visibility section.
The attribute conn_counter is underlined, which denotes a static attribute. You declare static
attributes using the CLASS-DATA statement. The syntax of CLASS-DATA is identical to that
of DATA.

Note:
We begin with public attributes at this point. Later in the course, when we discuss
encapsulation, we will turn them into private attributes.

© Copyright. All rights reserved. 109


Unit 3: Local Classes

110 © Copyright. All rights reserved.


Unit 3
Exercise 4
Define a Local Class

1. Create a new ABAP class called ZCL_##_LOCAL_CLASS, where ## is your group number.
Ensure that the class implements the interface IF_OO_ADT_CLASSRUN.

2. Create a new local class lcl_connection inside the global class. Use code completion to
generate the code.

3. In local class lcl_connection, declare the following public attributes:

Table 1: Attributes
Attribute Name Scope Data Type
carrier_id instance /DMO/CARRIER_ID

connection_id instance /DMO/CONNECTION_ID

conn_counter static I

4. Activate the class.

Note:
Because the if_oo_adt_classrun~main( ) method does not contain
executable code, yet, there is nothing to test or debug at this step.

© Copyright. All rights reserved. 111


Unit 3
Solution 4
Define a Local Class

1. Create a new ABAP class called ZCL_##_LOCAL_CLASS, where ## is your group number.
Ensure that the class implements the interface IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_LOCAL_CLASS, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

2. Create a new local class lcl_connection inside the global class. Use code completion to
generate the code.
a) Switch to the Local Types tab.

b) Type lcl into the editor and press Ctrl + Space.

c) Double-click lcl - class in the pop-up.

d) While lcl is still highlighted in the line class lcl definition create private.,
complete the name of the class to lcl_connection. Then delete the words create
private.

3. In local class lcl_connection, declare the following public attributes:

Table 1: Attributes
Attribute Name Scope Data Type
carrier_id instance /DMO/CARRIER_ID

connection_id instance /DMO/CONNECTION_ID

conn_counter static I

a) After line PUBLIC SECTION. and before line PROTECTED SECTION., add the
following three statements:

DATA carrier_id TYPE /dmo/carrier_id.


DATA connection_id TYPE /dmo/connection_id.

CLASS-DATA conn_counter TYPE i.

112 © Copyright. All rights reserved.


Lesson: Defining a local class

4. Activate the class.

Note:
Because the if_oo_adt_classrun~main( ) method does not contain
executable code, yet, there is nothing to test or debug at this step.

a) Press Ctrl + F3 to activate the class.

© Copyright. All rights reserved. 113


Unit 3: Local Classes

LESSON SUMMARY
You should now be able to:
● Define a local class inside a global class

114 © Copyright. All rights reserved.


Unit 3
Lesson 2
Creating Instances Of A Class

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Create Instances of an ABAP Class

Create Instances

Figure 72: Access to Static Attributes

You work with attributes like normal variables of the same type. Outside the class, however,
the attribute name is not sufficient to identify the attribute unambiguously. To address a
static attribute outside the class, first type the class name, then the static component
selector (=>), and only then the attribute name. The static component selector is a double
arrow made up of an equals sign and the greater than sign.

Hint:
No blanks are allowed before or after the component selector.

© Copyright. All rights reserved. 115


Unit 3: Local Classes

Figure 73: Reference Variables

For instance attributes the situation is even more complicated: In order to access an instance
component, you need a reference variable.
A reference variable is a special kind of variable that you use to create, address, and manage
an object. A reference variable is used to point at the instance of a class in the program
memory. You declare reference variables using the DATA statement with the addition TYPE
REF TO followed by the name of a class.
The initial value of a reference variable is called the NULL reference; the reference does not
yet point anywhere.

Figure 74: Creating an Instance of a Class

To create a new instance of a class, you use the NEW operator. The example above, uses a
NEW #( ) expression on the right hand side of a value assignment. The result of the
expression is the memory address of the newly created instance. This reference is then
stored in the reference variable on the left-hand side of the assignment.
You may have noticed that the name of the class that you want to instantiate does not appear
anywhere in the expression. However, from the location of the NEW #( ) expression, the

116 © Copyright. All rights reserved.


Lesson: Creating Instances Of A Class

system already knows that the target variable connection has the type REF TO lcl_connection,
and consequently it knows that it should create an instance of the class lcl_connection. The
pound sign after the NEW operator means "use the type of the variable before the equals
sign". (In more advanced scenarios, you can actually specify the name of the class in place of
the pound sign).

Hint:
There must be at least one blank between the brackets.

When you address a class for the first time (which could be accessing a static component or
creating an instance of the class), the runtime system also loads the class definition into the
program memory. This class definition contains all of the static attributes, which only exist
once in the class instead of once for each instance.

Figure 75: Access to Instance Attributes of a Class

You address static components using the class name and the static component selector. This
does not work for instance components because you have to specify the instance you want to
access.
To address an instance attribute outside the class, first type the reference variable, then the
instance component selector (->), and only then the attribute name. The instance component
selector is an arrow made up of a dash and the greater than sign.

Note:
Unlike many other programming languages, ABAP uses different characters for
instance component selector and static component selector.

© Copyright. All rights reserved. 117


Unit 3: Local Classes

Figure 76: Creating Multiple Instances of a Class

One of the main characteristics of object oriented programming is the fact that you can create
multiple instances of the same class. Each instance is created in a different place in the
program memory and the values of instance attributes in one instance are independent from
the values in other instances. But as the graphic illustrates, instances of the same class share
the value for the static attributes.

Figure 77: Copying Reference Variables

If you assign one reference variable to another, the system copies the address of the object to
which the first variable is pointing into the second reference variable. The result of this is that
you have two reference variables that point to the same object.

118 © Copyright. All rights reserved.


Lesson: Creating Instances Of A Class

Figure 78: Overwriting Reference Variables

You can use the same reference variable to create more than one instance of a class. Each
time you use the NEW #( ) expression, the system creates a new instance of the class and
places the address of the new instance into the reference variable. However, the address of
the new instance overwrites the address of the previous instance.
In the example above, the address of lcl_connection (2) overwrites the address of
lcl_connection (1). Consequently, there is no longer a reference variable in the program
pointing to lcl_connection (1). When this happens to an instance, it can no longer be
addressed from the program.
To prevent the program memory from becoming filled with objects that can no longer be
addressed and eventually overflowing, the runtime system has a component called the
garbage collector. The garbage collector is a program that runs periodically to look for and
destroy objects to which no more references point. If during a program you delete the last
reference to an object by overwriting it or using the CLEAR statement, the garbage collector
will destroy the object on its next pass.

Note:
At the end of a program, when all of the reference variables are freed, the garbage
collector will destroy all of the instances to which they had pointed. You do not
have to worry about resource management in the program yourself.

© Copyright. All rights reserved. 119


Unit 3: Local Classes

Managing Instances In An Internal Table

Figure 79: Storing References in an Internal Table

One way in which you can keep objects alive is to place the references into an internal table.
This is a technique that you may well want to use if you are creating a whole series of objects.
It enables you to use a single reference variable to create lots of objects. Although the
reference variable is overwritten with the address of the next object, the existing objects are
safe because the internal table contains a reference to them. You therefore never delete the
"last" reference to the objects.
Class zcl_s4d400_class

120 © Copyright. All rights reserved.


Unit 3
Exercise 5
Create and Manage Instances

Task 1: Preparation

1. If you finished the previous exercise Define a Local Class, create a copy of your global class
ZCL_##_LOCAL_CLASS, and name the copy ZCL_##_INSTANCES, where ## is your group
number. Then skip the rest of this task.

2. If you did not finish the previous exercise, create a new global class ZCL_##_INSTANCES,
where ## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.

3. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

DATA carrier_id TYPE /dmo/carrier_id.


DATA connection_id TYPE /DMO/Connection_id.

CLASS-DATA conn_counter TYPE i.

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

ENDCLASS.

Task 2: Create an Instance

1. In method if_oo_adt_classrun~main( ) of your global class, declare a reference


variable with the type of your local class lcl_connection.

2. Create an instance of the class and set the attributes carrier_id and connection_id
(Suggested values: “LH” for attribute carrier_id and “0400”for attribute
connection_id.

3. Activate the class and use the Debugger to analyze step by step what happens.

© Copyright. All rights reserved. 121


Unit 3: Local Classes

Task 3: Manage Several Instances

1. In method if_oo_adt_classrun~main( ) of your global class, declare an internal table


with the line type TYPE REF TO lcl_connection.

2. After instantiating the class and setting the attributes, append the object reference to the
internal table.

3. Create two more instances of class lcl_connection, set their instance attributes to
different values as in the first instance and append the references to the new instances to
internal table connections. Use the same reference variable connection for all three
instances.

4. Activate the class and use the Debugger to analyze step by step what happens.

122 © Copyright. All rights reserved.


Unit 3
Solution 5
Create and Manage Instances

Task 1: Preparation

1. If you finished the previous exercise Define a Local Class, create a copy of your global class
ZCL_##_LOCAL_CLASS, and name the copy ZCL_##_INSTANCES, where ## is your group
number. Then skip the rest of this task.
a) In the Project Explorer view on the left, expand your package.

b) Expand node Source Code Library → Classes

c) Right-click the name of the class you want to copy and choose Duplicate.

d) In the Name field, enter the name ZCL_##_INSTANCES, where ## is your group
number.

e) Choose Next.

f) Select your transport request and choose Finish.

2. If you did not finish the previous exercise, create a new global class ZCL_##_INSTANCES,
where ## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_INSTANCES, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

3. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

DATA carrier_id TYPE /dmo/carrier_id.


DATA connection_id TYPE /DMO/Connection_id.

CLASS-DATA conn_counter TYPE i.

© Copyright. All rights reserved. 123


Unit 3: Local Classes

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

ENDCLASS.

a) Navigate to the Local Types tab and insert the source code.

Task 2: Create an Instance

1. In method if_oo_adt_classrun~main( ) of your global class, declare a reference


variable with the type of your local class lcl_connection.
a) Switch to the Global Class tab and, between METHOD if_oo_adt_classrun~main.
and ENDMETHOD. enter the following:
DATA connection TYPE REF TO lcl_connection.

2. Create an instance of the class and set the attributes carrier_id and connection_id
(Suggested values: “LH” for attribute carrier_id and “0400”for attribute
connection_id.
a) Add the following code to your class after the DATA statement:

connection = new #( ).

connection->carrier_id = 'LH'.
connection->connection_id = '0400'.

Hint:
After typing the component selector (->), press Strg + Space to choose
the attribute names from a suggestion list.

3. Activate the class and use the Debugger to analyze step by step what happens.
a) Press Ctrl + F3 to activate the class.

b) Double-click the left-hand margin of the editor next to the line connection = new
#( ).to set a break point.

c) Press F9 to run the class.

d) Double-click the word connection to display the content of reference variable


connection.

e) Press F5 to go one step further in the debugger. Check that the value of connection
has changed.

f) In the Variables view, expand the branch connection to display the initial attributes of
the class.

124 © Copyright. All rights reserved.


Lesson: Creating Instances Of A Class

g) Press F5 to go one step further in the debugger. Check that the value of carrier_id
has changed.

h) Press F5 again. Check that the value of Connection_ID has changed.

Task 3: Manage Several Instances

1. In method if_oo_adt_classrun~main( ) of your global class, declare an internal table


with the line type TYPE REF TO lcl_connection.
a) Between METHOD if_oo_adt_classrun~main. and ENDMETHOD., under the
existing DATA statement, enter the following: DATA connections TYPE TABLE OF
REF TO lcl_connection..

2. After instantiating the class and setting the attributes, append the object reference to the
internal table.
a) Change your code so that it looks like this:

connection = NEW #( ).

connection->carrier_id = 'LH'.
connection->connection_id = '0400'.

APPEND connection TO connections.

3. Create two more instances of class lcl_connection, set their instance attributes to
different values as in the first instance and append the references to the new instances to
internal table connections. Use the same reference variable connection for all three
instances.
a) Before ENDMETHOD., add the following code:

connection->carrier_id = 'AA'.
connection->connection_id = '0017'.

APPEND connection TO connections.

connection = NEW #( ).

connection->carrier_id = 'SQ'.
connection->connection_id = '0001'.

APPEND connection TO connections.

4. Activate the class and use the Debugger to analyze step by step what happens.
a) Press Ctrl + F3 to activate the class.

b) Double-click the left-hand margin of the editor next to the first line connection =
new #( ).to remove the break point.

c) Double-click the left-hand margin of the editor next to the first line APPEND
connection TO connections.to set a new break point.

d) Press F9 to run the class.

e) Double-click the word connection to display the content of reference variable


connection.

© Copyright. All rights reserved. 125


Unit 3: Local Classes

f) Double-click the word connections to display the content of internal table


connections.

g) Press F5 to go one step further in the debugger. Check that the content of
connections has changed.

h) In the Variablesview, expand the branch connections to display content of the


internal table.

i) Press F5 several times until you reach the end of the program. While you do so, check
the content of the internal table.

126 © Copyright. All rights reserved.


Lesson: Creating Instances Of A Class

LESSON SUMMARY
You should now be able to:
● Create Instances of an ABAP Class

© Copyright. All rights reserved. 127


Unit 3
Lesson 3
Defining And Calling Methods

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Define and call methods

Defining Methods

Figure 80: Method Definition

In the definition part of a class you use METHODS to define an instance method and CLASS-
METHODS to define a static method. The name of the method is followed by the method's
signature; that is, the set of values that the method exchanges with its caller and the
exceptions that may arise during the method.
The signature of a method consists of parameters and exceptions. Each parameter has a
name and a type.
ABAP knows the following kinds of parameters:

Importing Parameters
Importing parameters are values that the method receives from the caller. A method can
have any number of importing parameters.
By default, importing parameters are mandatory, but there are two ways to make them
optional:

128 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

● Using the OPTIONAL addition. The parameter is optional and its default value is the
initial value appropriate to the type of the parameter
● Using the DEFAULT <val> addition. The parameter is optional and its default value is
the value that you specified as <val>.

Inside of a method, you may not change importing parameters. If you attempt to do so,
you will cause a syntax error.
Exporting Parameters
Exporting parameters are results that are returned by the method. A method can have
any number of exporting parameters. All exporting parameters are optional - a calling
program only uses the values that it actually needs.
Changing Parameters
Changing parameters are values that the method receives from the caller. Unlike
importing parameters, the method can change the values of these parameters. They are
then returned to the caller under the same name. A method can have any number of
changing parameters. Changing parameters are mandatory by default; you can make
them optional in the same way as importing parameters.
Returning Parameters
A returning parameter is a method result that can be used directly in an expression. A
method can only have one returning parameter. Returning parameters have to use a
special form of parameter passing which is called pass-by-value. This form of parameter
passing is defined by surrounding the parameter name in brackets (no blanks!) and
preceding it with keyword VALUE.

Keyword RAISING is used to list the exceptions the method might raise to indicate an error
situation. The calling program can then react to the error.

Animation
For more information on this topic please view the animation in the lesson
Defining And Calling Methods in your online course.

Figure 81: Example: Methods of the Flight Connection Class

© Copyright. All rights reserved. 129


Unit 3: Local Classes

As an example, add two methods to our class lcl_connection.


A set_attributes( ) method to set the values for attribute i_carrier_id and i_connection_id and
a get_attributes( ) method to return the values of these attributes. Where set_attributes( )
needs two importing parameters, one for each of attribute, the get_attributes( ) method
needs two exporting parameters.
For every method that you define, you must also create an implementation in the
implementation part of the class. Until you do so, you see syntax errors in your class; the
syntax check tells you that the implementation of the method is missing.

Hint:
ADT offers a quickfix to add the missing implementation. To use this quick fix,
proceed as follows:

1. Position the cursor in a METHODS statement with an error and press Ctrl +
1.

2. From the list of possible quick fixes choose Add implementation for … and
press Enter . If the implementation is missing for several methods, the
quickfix title reads Add … unimplemented methods.

Implementing Methods

Figure 82: Implementing Methods

You must implement every method that you define. You do this in the implementation part of
the class, by adding a pair of statements METHOD <method_name> and ENDMETHOD.
The method implementation contains ABAP statements that can access the parameters of
the method (you are not allowed to change importing parameters) and all types, attributes,
and constants that you declared in the class, independent from their visibility. Instance
methods may access both instance attributes and static attributes. Static methods may only
access static components.
Inside the implementation part of a class, you can access the attributes of that class without a
reference variable and '->' (or the class name and '=>' , in case of static attributes).

130 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

Figure 83: The Need for Self-Reference ME->

Only in the implementation of instance methods, ABAP offers built-in variable ME. ME is a
reference variable, typed with the current class and filled at runtime with the address of the
current instance. The use of ME is optional and should be avoided, unless the name of an
attribute collides with the name of another data object, for example a parameter name.
In the example, the import parameters of method set_attributes( ) have the same names as
the corresponding attributes. In such a situation, the name by itself denotes the parameter.
Only by putting me-> in front it becomes clear that an attribute of the current instance is to be
accessed.

Figure 84: Raising Exceptions

If an error occurs during the execution of a method, the method can trigger an exception
using statement RAISE EXCEPTION TYPE, followed by the name of the exception.

© Copyright. All rights reserved. 131


Unit 3: Local Classes

Note:
Technically, exception names are the names of special ABAP classes and
statement RAISE EXCEPTION TYPE creates an instance of the referenced class.
The instance is referred to as exception object and the special kind of ABAP
classes are called exception classes.

The moment an exception is raised, the method execution is terminated.


Control is returned to the calling program if all prerequisites are met. Otherwise the entire
program terminates with a runtime error.
The prerequisites for continuing the program are as follows:
● The raised exception is declared in the RAISING clause of the method signature
● The method call is surrounded by a TRY … ENDTRY control structure
● The TRY … ENDTRY control structure contains a CATCH block for the exception

Note:
For some exceptions, the ABAP editor displays a syntax warning with a quick fix
when you raise an exception that is not yet declared in the RAISING clause of the
method.

Calling Methods

Figure 85: Calling Methods

You call an instance method using a reference variable and the instance component selector
(->). The component selector is followed by the name of the method you want to call. For
static methods you use the class name and the static component selector (=>). On both
cases, the parameter passing takes place in a pair of brackets. The brackets are needed in any
case. They remain empty if no parameters are to be passed.

132 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

Note:
No blank is allowed between the method name and the opening bracket. On the
other hand you need at least one blank after the opening bracket and before the
closing bracket.

Importing parameters are listed after keyword EXPORTING because the values that are
imported by the called method are exported by the calling program. The parameter names
are listed on the left-hand side of an equals sign (=) and an expression on the right-hand side..
This expression can be as simple as a literal, constant, or variable but any other expressions
are also allowed as long as the type of the expression matches the type of the parameter.
Exporting parameters are listed after keyword IMPORTING. Note, that for exporting
parameter the parameter name is also listed on the left-hand side of the equals sign. The
variable on the right-hand side has to have the same type as the parameter.
Changing parameters are listed after keyword CHANGING. The type of the variable on the
right-hand side has to match the type of the parameter on the left hand side.

Figure 86: Examples for Method Calls

The example illustrates the call of instance methods set_attributes( ) and get_attributes( ).
The parameter names are always on the left-hand side of the equals sign (=).

Hint:
You can use code completion in ADT to generate the method call including the
parameter passing. To do so, proceed as follows:

1. Type in the reference variable (or class name) and the component selector.

2. Once you typed the component selector press Ctrl + Space to display a
list of components you can address.

3. If you choose a method, and press Shift + Enter to insert the name of the
method and its full signature into your code. Optional parameters are listed in
comment lines.

© Copyright. All rights reserved. 133


Unit 3: Local Classes

Figure 87: Short Forms for Method Calls

When calling a method, keyword IMPORTING is always needed to receive the value of
exporting parameters. But keyword EXPORTING becomes optional, if you only want to supply
importing parameters.
For methods with only one mandatory importing parameter, you can even omit the explicit
parameter assignment. In the example, parameter i_carrier_id is optional with default value
'LH'. Therefore the value between the brackets is assigned to the remaining mandatory
importing parameter i_connection_id.

Raising Exceptions

Figure 88: Handling Exceptions raised by Methods

In a previous section of this class, you learned how to handle runtime errors with TRY …
ENDTRY control structures.
Exceptions declared in the RAISING clause of a method definition are handled in exactly the
same way:
● Place the method call in the TRY-block of the TRY … ENDTRY control structure.

134 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

● Define a CATCH block with the name of the exception you want to handle.

Note:
If there is code that you want to skip in case the method call failed, you can place
this code inside the try block, after the method call.

Try It Out: Method Calls and Exception Handling


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

CONSTANTS c_carrier_id TYPE /dmo/carrier_id VALUE 'LH'.


CONSTANTS c_connection_id TYPE /dmo/connection_id VALUE '0400'.

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* Create Instance
**********************************************************************

connection = NEW #( ).

* Call Method and Handle Exception


**********************************************************************
out->write( |i_carrier_id = '{ c_carrier_id }' | ).
out->write( |i_connection_id = '{ c_connection_id }'| ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = c_carrier_id
i_connection_id = c_connection_id
).

APPEND connection TO connections.


out->write( `Method call successful` ).
CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

3. Navigate to tab Local Typesand insert the following code snippet there:

CLASS lcl_connection DEFINITION.


PUBLIC SECTION.

* Attributes
DATA carrier_id TYPE /dmo/carrier_id.
DATA connection_id TYPE /dmo/connection_id.

* Methods
METHODS set_attributes
IMPORTING
i_carrier_id TYPE /dmo/carrier_id DEFAULT 'LH'
i_Connection_id TYPE /dmo/connection_id
RAISING
cx_abap_invalid_value.

© Copyright. All rights reserved. 135


Unit 3: Local Classes

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD set_attributes.

IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.


RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

carrier_id = i_carrier_id.
connection_id = i_connection_id.

ENDMETHOD.

ENDCLASS.

4. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

5. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts. In particular, change the values of the two constants to debug
the raising of the exception.

Functional Methods

Figure 89: Functional Methods

Methods that have a returning parameter are called functional methods. It is not possible to
define more than one returning parameter for the same method. It is mandatory that you
define the returning parameter in the form VALUE(<parameter_name>). Besides the
returning parameter a functional method can have any combination of other parameters. It is
most common however, to add importing parameters only. The reason is, that with additional
exporting or changing parameters you loose the biggest advantage of functional methods,
namely, that you can use the result of a functional method directly in other ABAP expressions.
The figure shows two examples of how you can use functional methods in expressions; the
first is a simple example in which the returning parameter is assigned directly to a variable.
The second example shows how the call of the functional method is used as input for another
method. The system executes the functional method, and then uses the value of the returning
parameter as input for method write( ).

136 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

Try It Out: Functional Methods


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* Create Instance
**********************************************************************

connection = NEW #( ).

connection->set_attributes(
EXPORTING
i_carrier_id = 'LH'
i_connection_id = '0400'
).

APPEND connection TO connections.

* Calling Functional Method


**********************************************************************
" in a value assignment (with inline declaration for result)
DATA(result) = connection->get_output( ).

" in logical expression


IF connection->get_output( ) IS NOT INITIAL.

" as operand in a statement


LOOP AT connection->get_output( ) INTO DATA(line).

ENDLOOP.

" to supply input parameter of another method


out->write( data = connection->get_output( )
name = ` ` ).

ENDIF.

3. Navigate to tab Local Typesand insert the following code snippet there:

CLASS lcl_connection DEFINITION.


PUBLIC SECTION.

* Attributes
DATA carrier_id TYPE /dmo/carrier_id.
DATA connection_id TYPE /dmo/connection_id.

* Methods
METHODS set_attributes
IMPORTING
i_carrier_id TYPE /dmo/carrier_id DEFAULT 'LH'
i_Connection_id TYPE /dmo/connection_id.

" Functional Method


METHODS get_output
RETURNING VALUE(r_output) TYPE string_table.

© Copyright. All rights reserved. 137


Unit 3: Local Classes

* PROTECTED SECTION.

* PRIVATE SECTION.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD set_attributes.

carrier_id = i_carrier_id.
connection_id = i_connection_id.

ENDMETHOD.

METHOD get_output.

APPEND |------------------------------| TO r_output.


APPEND |Carrier: { carrier_id }| TO r_output.
APPEND |Connection: { connection_id }| TO r_output.

ENDMETHOD.

ENDCLASS.

4. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

5. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts. In particular, debug the different calls of functional method
get_output( )..

138 © Copyright. All rights reserved.


Unit 3
Exercise 6
Define and Call Methods

Task 1: Preparation

1. If you finished the previous exercise Create and Manage Instances, create a copy of your
global class ZCL_##_INSTANCES, and name the copy ZCL_##_METHODS, where ## is your
group number. Then skip the rest of this task.

2. If you did not finish the previous exercise, create a new global class ZCL_##_METHODS,
where ## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************

connection = NEW #( ).

connection->carrier_id = 'LH'.
connection->connection_id = '0400'.

APPEND connection TO connections.

* Second Instance
**********************************************************************

connection = NEW #( ).

connection->carrier_id = 'AA'.
connection->connection_id = '0017'.

APPEND connection TO connections.

* Third Instance
**********************************************************************

connection = NEW #( ).

connection->carrier_id = 'SQ'.
connection->connection_id = '0001'.

APPEND connection TO connections.

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

© Copyright. All rights reserved. 139


Unit 3: Local Classes

PUBLIC SECTION.

DATA carrier_id TYPE /dmo/carrier_id.


DATA connection_id TYPE /dmo/connection_id.

CLASS-DATA conn_counter TYPE i.

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

ENDCLASS.

Task 2: Define Methods

1. Switch to the local class lcl_connection.

2. Add a method get_output to the public section of the class. It should have one returning
parameter r_outputof global table typeSTRING_TABLE.

Note:
Remember to surround the name of the returning parameter with VALUE( ).

3. Add a method set_attributes to the public section of the class. It should have one
importing parameter for each instance attribute of the class. Use the same types for the
parameters that you used to type the attributes. To distinguish the parameters from the
attributes, add prefix i_ to the parameter names. In addition, the method should raise
exception CX_ABAP_INVALID_VALUE.

Task 3: Implement Methods

1. Use a quick fix to add the method implementations to the class.

2. Implement method get_output. Append some string templates to returning parameter


r_output. In the string templates, use embedded expressions to add the values of
attributes carrier_id and connection_id.

3. Implement method set_attributes. If either of the two importing parameters is empty


(IS INITIAL), raise exception CX_ABAP_INVALID_VALUE. Otherwise, fill the two
instance attributes with the values of the importing parameters.

4. Activate your class.

Task 4: Call a Functional Method

1. Switch to the implementation of method if_oo_adt_classrun~main( ) in the global


class.

140 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

2. At the end of the method, add a loop over internal table connectionswith reference
variable connection as work area.

3. In the loop, call functional method get_output( ) for each instance in turn and write the
result to the console.

Hint:
You can use the call of method get_output( ) directly as input for out-
>write( ).

4. Activate the class. Execute it as console app and analyze the console output.

Task 5: Use Code Completion And Handle Exceptions

1. For the first instance of class lcl_connection, replace the direct access to attributes
carrier_id and connection_idwith a call of instance method set_attributes( ).
Use code completion to insert the full signature of the method.

Hint:
Press Ctrl + Space after you typed the component select (->) to display a
list of available attributes and methods. Choose the method and then press
Shift + Enter to insert the full signature of the method.

2. Handle the exception. Surround the method call with TRY. and ENDTRY.. Add a CATCH-
Block to handle exception CX_ABAP_INVALID_VALUE. Make sure the new instance is only
added to internal table connections if the method call was successful.

3. Repeat the previous step for the other two instances of class lcl_connection.

4. Activate the class. Execute it and debug the method calls.

© Copyright. All rights reserved. 141


Unit 3
Solution 6
Define and Call Methods

Task 1: Preparation

1. If you finished the previous exercise Create and Manage Instances, create a copy of your
global class ZCL_##_INSTANCES, and name the copy ZCL_##_METHODS, where ## is your
group number. Then skip the rest of this task.
a) In the Project Explorer view on the left, expand your package.

b) Expand node Source Code Library → Classes

c) Right-click the name of the class you want to copy and choose Duplicate.

d) In the Name field, enter the name ZCL_##_METHODS, where ## is your group number.

e) Choose Next.

f) Select your transport request and choose Finish.

2. If you did not finish the previous exercise, create a new global class ZCL_##_METHODS,
where ## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_METHODS, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************

connection = NEW #( ).

connection->carrier_id = 'LH'.
connection->connection_id = '0400'.

142 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

APPEND connection TO connections.

* Second Instance
**********************************************************************

connection = NEW #( ).

connection->carrier_id = 'AA'.
connection->connection_id = '0017'.

APPEND connection TO connections.

* Third Instance
**********************************************************************

connection = NEW #( ).

connection->carrier_id = 'SQ'.
connection->connection_id = '0001'.

APPEND connection TO connections.

a) Navigate to the Global Class tab and insert the source code between METHOD
if_oo_adt_classrun~main. and ENDMETHOD..

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

DATA carrier_id TYPE /dmo/carrier_id.


DATA connection_id TYPE /dmo/connection_id.

CLASS-DATA conn_counter TYPE i.

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

ENDCLASS.

a) Navigate to the Local Types tab and insert the source code.

Task 2: Define Methods

1. Switch to the local class lcl_connection.


a) In the global class, choose Local Types.

2. Add a method get_output to the public section of the class. It should have one returning
parameter r_outputof global table typeSTRING_TABLE.

© Copyright. All rights reserved. 143


Unit 3: Local Classes

Note:
Remember to surround the name of the returning parameter with VALUE( ).

a) Enter the following code before the PROTECTED SECTION statement:

METHODS get_output
RETURNING
VALUE(r_output) TYPE STRING_TABLE.

Note:
For the moment, ignore syntax error Implementation missing for method
"GET_OUTPUT".

3. Add a method set_attributes to the public section of the class. It should have one
importing parameter for each instance attribute of the class. Use the same types for the
parameters that you used to type the attributes. To distinguish the parameters from the
attributes, add prefix i_ to the parameter names. In addition, the method should raise
exception CX_ABAP_INVALID_VALUE.
a) Enter the following code before the PROTECTED SECTION statement:

METHODS set_attributes
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
i_connection_id TYPE /dmo/connection_id
RAISING
cx_abap_invalid_value.

Note:
For the moment, ignore syntax error Implementation missing for method
"SET_ATTRIBUTES".

Task 3: Implement Methods

1. Use a quick fix to add the method implementations to the class.


a) Position the cursor on the name of one of the methods in the editor and press Ctrl +
1.

b) Double-click the suggestion Add 2 unimplemented methods.

2. Implement method get_output. Append some string templates to returning parameter


r_output. In the string templates, use embedded expressions to add the values of
attributes carrier_id and connection_id.
a) In the local class add the following code between the statements METHOD
get_output. and ENDMETHOD.

APPEND |------------------------------| TO r_output.


APPEND |Carrier: { carrier_id }| TO r_output.
APPEND |Connection: { connection_id }| TO r_output.

144 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

3. Implement method set_attributes. If either of the two importing parameters is empty


(IS INITIAL), raise exception CX_ABAP_INVALID_VALUE. Otherwise, fill the two
instance attributes with the values of the importing parameters.
a) In the local class add the following code between the statements METHOD
set_attributes. and ENDMETHOD.

IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.


RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

carrier_id = i_carrier_id.
connection_id = i_connection_id.

4. Activate your class.


a) Choose Ctrl + F3 to activate the class.

Task 4: Call a Functional Method

1. Switch to the implementation of method if_oo_adt_classrun~main( ) in the global


class.
a) In the global class, choose Global Class scroll down to the implementation of method
if_oo_adt_classrun~main( ).

2. At the end of the method, add a loop over internal table connectionswith reference
variable connection as work area.
a) Add the following code before ENDMETHOD..

LOOP AT connections INTO connection.

ENDLOOP.

3. In the loop, call functional method get_output( ) for each instance in turn and write the
result to the console.

Hint:
You can use the call of method get_output( ) directly as input for out-
>write( ).

a) Add the following code between LOOP AT connections INTO connection and
ENDLOOP.

LOOP AT connections INTO connection.

out->write( connection->get_output( ) ).

ENDLOOP.

4. Activate the class. Execute it as console app and analyze the console output.
a) Press Ctrl + F3 to activate the class.

b) Press F9 to run the class.

c) Analyze the output on the Console window.

© Copyright. All rights reserved. 145


Unit 3: Local Classes

Task 5: Use Code Completion And Handle Exceptions

1. For the first instance of class lcl_connection, replace the direct access to attributes
carrier_id and connection_idwith a call of instance method set_attributes( ).
Use code completion to insert the full signature of the method.

Hint:
Press Ctrl + Space after you typed the component select (->) to display a
list of available attributes and methods. Choose the method and then press
Shift + Enter to insert the full signature of the method.

a) Place the cursor in the next line after the first connection = NEW #( )..

b) Type connection-> and press Ctrl + Space.

c) Choose set_attributes and press Shift + Enter.

d) Pass values to the importing parameters. Use the same literals that you previously
used to set the attributes of this instance.

e) Remove or comment the direct access to the instance attributes for this instance.

2. Handle the exception. Surround the method call with TRY. and ENDTRY.. Add a CATCH-
Block to handle exception CX_ABAP_INVALID_VALUE. Make sure the new instance is only
added to internal table connections if the method call was successful.
a) Uncomment the generated code line CATCH cx_abap_invalid_value. .

b) Add TRY. before the method call .

c) Add ENDTRY. after the CATCH statement.

d) Between the CATCH statement and the ENDTRY statement add out-
>write( `Method call failed` ).

e) Move the APPEND statement up to between the method call and CATCH statement.

f) The complete method call should now look like this:

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'LH'
i_connection_id = '0400'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'LH'.
* connection->connection_id = '0400'.
* APPEND connection TO connections.

3. Repeat the previous step for the other two instances of class lcl_connection.

146 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

a) After this step, the implementation of method if_oo_adt_classrun~main( )


should read as follows:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************
connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'LH'
i_connection_id = '0400'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'LH'.
* connection->connection_id = '0400'.
* APPEND connection TO connections.

* Second instance
**********************************************************************

connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'AA'
i_connection_id = '0017'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'AA'.
* connection->connection_id = '0017'.
* APPEND connection TO connections.

* Third instance
**********************************************************************
connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'SQ'
i_connection_id = '0001'
).

APPEND connection TO connections.

© Copyright. All rights reserved. 147


Unit 3: Local Classes

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'SQ'.
* connection->connection_id = '0001'.
*
* APPEND connection TO connections.

* Output
**********************************************************************

LOOP AT connections INTO connection.

out->write( connection->get_output( ) ).

ENDLOOP.

ENDMETHOD.

4. Activate the class. Execute it and debug the method calls.


a) Press Ctrl + F3 to activate the class.

b) Press F9 to run the class.

148 © Copyright. All rights reserved.


Lesson: Defining And Calling Methods

LESSON SUMMARY
You should now be able to:
● Define and call methods

© Copyright. All rights reserved. 149


Unit 3
Lesson 4
Using Encapsulation To Ensure Consistency

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Explain Encapsulation
● Define and Use Constructors

Data Encapsulation

Figure 90: Object Oriented Programming - Data Encapsulation

In object-oriented programming, an object corresponds to a real-life object such as an


employee, a vehicle, or, in our case, a flight connection. It has attributes that describe it, in the
case of a flight connection, those are the carrier id and the flight number.
Now let us consider what happens when a program that is using this object wants to provide
values for these attributes. It is obvious that only those combinations of carrier id and flight
number should be accepted that correspond to a flight connection in the real world.
In object orientation, the client program should not be able to change the attribute values
directly. Instead, it should need to call a method to perform this task. The method, which
comes with the object, can then check whether the combination of carrier id and flight
number is valid and, if this is not the case - reject the change.
As developers of class lcl_connection, we can ensure the use of method set_attributes( ) by
making attributes carrier_id and connection_id private, or at least read only.
This concept is called data encapsulation; The information about the flight connection is
managed by the connection object itself and cannot be manipulated by anyone else. This

150 © Copyright. All rights reserved.


Lesson: Using Encapsulation To Ensure Consistency

ensures that no other point in the program can bypass the check of the consistency - either
knowingly or unknowingly. This is one of the major advantages of object-orientation.

Note:
In object oriented programming, it is recommended to use data encapsulation as
much as possible!

Figure 91: Read-only Attributes and Private Attributes

With the public attributes we defined by now, it was possible to read and change the values of
the attributes anywhere inside and outside the class.
In order to restrict access to the attributes you have two options:

1. Keep the DATA statement or CLASS-DATA statement in the public section and add
addition READ-ONLY. In doing so, write access to the attribute is forbidden outside of the
class, but read access is still possible.

Note:
Addition READ-ONLY is only allowed in the public section of a class.

2. Move the DATA statement or CLASS-DATA statement from the public section to one of
the other visibility sections, for example the private section. In doing so, read access and
write access to the attribute is forbidden outside of the class.

Hint:
ADT offers a quick fix to change the visibility of an attribute. To use it place
the cursor in the attribute name, press Ctrl + 1, and choose Make
<attribute> private.

© Copyright. All rights reserved. 151


Unit 3: Local Classes

Use The Instance Constructor

Figure 92: Motivation for Constructor Methods

By making your attributes private - or read-only, at least - you can ensure that the client
program uses the available set_attributes( ) method to set the values for attributes carrier_id
and connection_id.
But there is still potential for inconsistencies:
● You cannot force the program to call set_attributes( ) for each new instance. As a result,
there can be instances with initial values for carrier_id and connection_id.
● The client program can call set_attributes( ) several times for the same instance. This
should also not be possible.

What you need is a technique to enforce non-initial values during instantiation and to prevent
later changes.
To solve these problems, object-oriented programming languages use constructor methods.

Figure 93: Constructor Method Definition

The runtime system calls the constructor automatically when you create a new instance of
the class, but you may not call it explicitly. Thus the constructor is guaranteed to run once and
once only for each instance that you create.

152 © Copyright. All rights reserved.


Lesson: Using Encapsulation To Ensure Consistency

From a syntax perspective a constructor method has following properties:


● a public instance method with the reserved name constructor
● may have importing parameters, for example to obtain starting values for the attributes of
the new instance
● may raise exceptions

Note:
In ABAP, it is not possible to define more than one constructor method in the
same class.

Hint:
In ADT, you can use a quick fix to generate a constructor method. To use this
quick fix proceed as follows:

1. Either in the definition or implementation part, place the cursor in the class
name and press Ctrl + 1.

2. From the list of available quick fixes, choose Generate constructor

3. On the dialog window that appears, select the attributes you want to initialize
with the constructor and choose Finish

Once you generated the constructor you can adjust its definition and
implementation to your needs.

Figure 94: Example: Constructor Definition and Implementation (Generated)

The example shows the constructor of class lcl_connection. The generated definition contains
an importing parameter for each of the attributes carrier_id and connection_id. The
generated parameters have the same names as the related attributes.

© Copyright. All rights reserved. 153


Unit 3: Local Classes

The generated part of the implementation contains a value assignment for each of the
attributes with the related importing parameter on the right. Self-reference me-> is needed to
distinguish the attributes from the parameters of identical name.

Figure 95: Adjusting the Generated Constructor

The example shows some manual additions to the generated constructor of class
lcl_connection.
In order to reject the creation of instances with initial values, a consistency check was added
to the implementation and a RAISING clause to the definition of the constructor.
Because the constructor is executed once and only once for each new instance of class
lcl_connection, the constructor implementation is the perfect place to increment static
attribute conn_counter.

Figure 96: Instantiating Classes That have a Constructor

When you instantiate a class that has a constructor, the system calls the constructor method
automatically. If the constructor has importing parameters, you pass them in the NEW
expression exactly as you would pass parameters to a normal method.

154 © Copyright. All rights reserved.


Lesson: Using Encapsulation To Ensure Consistency

Note:
A constructor can have only importing parameters. Keyword EXPORTING is
neither needed nor allowed in the NEW expression.

Note:
If the constructor has exceptions, you must ensure that you catch them by
enclosing the instantiation in a TRY… CATCH...ENDTRY block. If an constructor
raises an exception, control returns immediately to the program containing the
NEW expression. In this case, you do not receive a new instance of the class.

Use The Static Constructor

Figure 97: Static Constructor Definition

While the instance constructor is called once when each instance of a class is created, you will
sometimes need to perform actions once only for the entire class. For this purpose ABAP
allows you to define a static constructor, also known as class constructor.
The runtime system calls the static constructor once only when the class is addressed for the
first time during the execution of a program.
The first addressing of a class could be one of the following:
● First instantiation of the class
● First call of a static method
● First access to a public static attribute

Note:
This list is not complete. There are other actions (related to inheritance) that can
cause a class to be addressed for the first time.

A typical use case for the static constructor is the dynamic initialization of static attributes
with non-initial values. Therefore it is important that the runtime calls the static constructor
before creating the instance, calling the static method, or addressing the static attribute.
From a syntax perspective a constructor method has following properties:
● A public static method with the reserved name class_constructor
● Without parameters or exceptions

© Copyright. All rights reserved. 155


Unit 3: Local Classes

Note:
A static constructor must not have a signature because it is impossible to tell
exactly when a class will be addressed for the first time.

Hint:
In ADT, you can use a quick fix to generate a class constructor method. To use
this quick fix proceed as follows:

1. Either in the definition or implementation part, place the cursor in the class
name and press Ctrl + 1.

2. From the list of available quick fixes, choose Generate class constructor

156 © Copyright. All rights reserved.


Unit 3
Exercise 7
Use Private Attributes and Constructors

Task 1: Preparation

1. If you finished the previous exercise Define and Implement Methods, create a copy of your
global class ZCL_##_METHODS, and name the copy ZCL_##_CONSTRUCTORS, where ## is
your group number. Then skip the rest of this task.

2. If you did not finish the previous exercise, create a new global class
ZCL_##_CONSTRUCTORS, where ## is your group number. Ensure that the class
implements the interface IF_OO_ADT_CLASSRUN.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************
connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'LH'
i_connection_id = '0400'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'LH'.
* connection->connection_id = '0400'.
* APPEND connection TO connections.

* Second instance
**********************************************************************

connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'AA'
i_connection_id = '0017'
).

APPEND connection TO connections.

© Copyright. All rights reserved. 157


Unit 3: Local Classes

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'AA'.
* connection->connection_id = '0017'.
* APPEND connection TO connections.

* Third instance
**********************************************************************
connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'SQ'
i_connection_id = '0001'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'SQ'.
* connection->connection_id = '0001'.
*
* APPEND connection TO connections.

* Output
**********************************************************************

LOOP AT connections INTO connection.

out->write( connection->get_output( ) ).

ENDLOOP.

ENDMETHOD.

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

DATA carrier_id TYPE /dmo/carrier_id.


DATA connection_id TYPE /dmo/connection_id.

CLASS-DATA conn_counter TYPE i.

METHODS set_attributes
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
i_connection_id TYPE /dmo/connection_id
RAISING
cx_abap_invalid_value.

METHODS get_output
returning

158 © Copyright. All rights reserved.


Lesson: Using Encapsulation To Ensure Consistency

value(r_output) type string_table.

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD get_output.

APPEND |------------------------------| TO r_output.


APPEND |Carrier: { carrier_id }| TO r_output.
APPEND |Connection: { connection_id }| TO r_output.

ENDMETHOD.

METHOD set_attributes.
IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

carrier_id = i_carrier_id.
connection_id = i_connection_id.

ENDMETHOD.

ENDCLASS.

Task 2: Make Attributes Private


Change the visibility of attributes carrier_id and connection_id to enforce the usage of
methods set_attributes( ) and get_output( ).

1. Set the visibility of attribute carrier_id to private using a quick fix.

2. Set the visibility of attribute connection_id to private using a quick fix.

Task 3: Create Instance Constructor


Replace public method set_attributes( ) with an instance constructor to ensure that the
attributes are set during the creation of a new instance and that they are not changed
afterward.

1. Comment the definition and implementation of method set_attributes( ).

2. Add an instance constructor to the local class lcl_connection using a quick fix. Ensure
that the constructor has importing parameters corresponding to attributes carrier_id
and connection_id.

3. Extend the generated constructor definition. Add exception CX_ABAP_INVALID_VALUE to


the definition of method constructor( ).

4. Extend the generated constructor implementation. If either of the importing parameters is


initial, raise exception CX_ABAP_INVALID_VALUE.

5. In the constructor implementation, add a statement to increase the value of static


attribute conn_counter by one. Make sure the statement is only executed if no exception
was raised.

© Copyright. All rights reserved. 159


Unit 3: Local Classes

Task 4: Use the Constructor


Adjust the instantiation of class lcl_connection to supply the parameters of the instance
constructor and handle the exception.

1. In method if_oo_adt_classrun~main( ), go to the NEW #( ) expression for the first


instance of lcl_connection.

2. In the NEW expression, supply the import parameters of constructor( ).

Hint:
You can copy the parameter passing from the call of method
set_attributes( ) for this instance.

3. Remove or comment the call of method set_attributes( ).

4. Move the instance creation into the TRY block of the exception handling.

5. Repeat the previous steps for the other instances of your local class.

6. Activate the class. Execute it and debug the instantiation.

160 © Copyright. All rights reserved.


Unit 3
Solution 7
Use Private Attributes and Constructors

Task 1: Preparation

1. If you finished the previous exercise Define and Implement Methods, create a copy of your
global class ZCL_##_METHODS, and name the copy ZCL_##_CONSTRUCTORS, where ## is
your group number. Then skip the rest of this task.
a) In the Project Explorer view on the left, expand your package.

b) Expand node Source Code Library → Classes

c) Right-click the name of the class you want to copy and choose Duplicate.

d) In the Name field, enter the name ZCL_##_CONSTRUCTORS, where ## is your group
number.

e) Choose Next.

f) Select your transport request and choose Finish.

2. If you did not finish the previous exercise, create a new global class
ZCL_##_CONSTRUCTORS, where ## is your group number. Ensure that the class
implements the interface IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_CONSTRUCTORS, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************
connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING

© Copyright. All rights reserved. 161


Unit 3: Local Classes

i_carrier_id = 'LH'
i_connection_id = '0400'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'LH'.
* connection->connection_id = '0400'.
* APPEND connection TO connections.

* Second instance
**********************************************************************

connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'AA'
i_connection_id = '0017'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'AA'.
* connection->connection_id = '0017'.
* APPEND connection TO connections.

* Third instance
**********************************************************************
connection = NEW #( ).

TRY.
connection->set_attributes(
EXPORTING
i_carrier_id = 'SQ'
i_connection_id = '0001'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* connection->carrier_id = 'SQ'.
* connection->connection_id = '0001'.
*
* APPEND connection TO connections.

* Output
**********************************************************************

LOOP AT connections INTO connection.

162 © Copyright. All rights reserved.


Lesson: Using Encapsulation To Ensure Consistency

out->write( connection->get_output( ) ).

ENDLOOP.

ENDMETHOD.

a) Navigate to the Global Class tab and insert the source code between METHOD
if_oo_adt_classrun~main. and ENDMETHOD..

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

DATA carrier_id TYPE /dmo/carrier_id.


DATA connection_id TYPE /dmo/connection_id.

CLASS-DATA conn_counter TYPE i.

METHODS set_attributes
IMPORTING
i_carrier_id TYPE /dmo/carrier_id
i_connection_id TYPE /dmo/connection_id
RAISING
cx_abap_invalid_value.

METHODS get_output
returning
value(r_output) type string_table.

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD get_output.

APPEND |------------------------------| TO r_output.


APPEND |Carrier: { carrier_id }| TO r_output.
APPEND |Connection: { connection_id }| TO r_output.

ENDMETHOD.

METHOD set_attributes.
IF i_carrier_id IS INITIAL OR i_connection_id IS INITIAL.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

carrier_id = i_carrier_id.
connection_id = i_connection_id.

ENDMETHOD.

ENDCLASS.

a) Navigate to the Local Types tab and insert the source code.

© Copyright. All rights reserved. 163


Unit 3: Local Classes

Task 2: Make Attributes Private


Change the visibility of attributes carrier_id and connection_id to enforce the usage of
methods set_attributes( ) and get_output( ).

1. Set the visibility of attribute carrier_id to private using a quick fix.


a) Go to the declaration of attribute carrier_id in local class lcl_connection.

b) Place the cursor on carrier_id and press Ctrl + 1.

c) Double-click the suggestion Make carrier_id private .

d) Check that the declaration of attribute carrier_id has moved to the private section.

2. Set the visibility of attribute connection_id to private using a quick fix.


a) Go to the declaration of attribute connection_id in local class lcl_connection.

b) Place the cursor on connection_id and press Ctrl + 1.

c) Double-click the suggestion Make connection_id private .

d) Check that the declaration of attribute connection_id has moved to the private
section.

Task 3: Create Instance Constructor


Replace public method set_attributes( ) with an instance constructor to ensure that the
attributes are set during the creation of a new instance and that they are not changed
afterward.

1. Comment the definition and implementation of method set_attributes( ).


a) Switch to the Local Types tab.

b) Select all lines that belong to the METHODS set_attributes statement, including the
line with the period sign (.).

c) Press Ctrl + < to add a star sign (*) in front of each selected line.

d) Select all lines that belong to the implementation of method set_attributes( )


including the corresponding ENDMETHOD. statement and press Ctrl + < again.

2. Add an instance constructor to the local class lcl_connection using a quick fix. Ensure
that the constructor has importing parameters corresponding to attributes carrier_id
and connection_id.
a) Place the cursor on the name of the class and press Ctrl + 1.

b) Double-click on Generate constructor.

c) In the dialog box, ensure that carrier_id and connection_id are selected and
choose Finish.

3. Extend the generated constructor definition. Add exception CX_ABAP_INVALID_VALUE to


the definition of method constructor( ).
a) Navigate to the generated definition of method constructor( ).

b) At the end of the METHODS statement, before the period sign, add RAISING
CX_ABAP_INVALID_VALUE .

164 © Copyright. All rights reserved.


Lesson: Using Encapsulation To Ensure Consistency

4. Extend the generated constructor implementation. If either of the importing parameters is


initial, raise exception CX_ABAP_INVALID_VALUE.
a) Navigate from the definition to the implementation of method constructor, for
example, by placing the cursor on constructor and pression F3.

b) After METHOD constructor, before the generated value assignments, add the
following code.

IF carrier_id IS INITIAL OR connection_id IS INITIAL.


RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

5. In the constructor implementation, add a statement to increase the value of static


attribute conn_counter by one. Make sure the statement is only executed if no exception
was raised.
a) After the generated value assignments, before ENDMETHOD., add conn_counter =
conn_counter + 1..

Task 4: Use the Constructor


Adjust the instantiation of class lcl_connection to supply the parameters of the instance
constructor and handle the exception.

1. In method if_oo_adt_classrun~main( ), go to the NEW #( ) expression for the first


instance of lcl_connection.
a) Switch to the Global Class tab.

b) Find the first line with connection = NEW #( )..

2. In the NEW expression, supply the import parameters of constructor( ).

Hint:
You can copy the parameter passing from the call of method
set_attributes( ) for this instance.

a) Adjust the NEW expression as follows:

connection = NEW #(
i_carrier_id = 'LH'
i_connection_id = '0400'
).

3. Remove or comment the call of method set_attributes( ).


a) Select all lines that belong to the connection->set_attributes( ... ).
statement, including the line with the closing bracket and the period sign (.).

b) Press Ctrl + < to add a star sign (*) in front of each selected line.

4. Move the instance creation into the TRY block of the exception handling.
a) Move the TRY. statement up, to before the instance creation.

b) Your first instance creation should now look like this:

TRY.

© Copyright. All rights reserved. 165


Unit 3: Local Classes

connection = NEW #(
i_carrier_id = 'LH'
i_connection_id = '0400'
).

* connection->set_attributes(
* EXPORTING
* i_carrier_id = 'LH'
* i_connection_id = '0400'
* ).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

5. Repeat the previous steps for the other instances of your local class.
a) The implementation of method if_oo_adt_classrun~main( ) should then look like
this:

METHOD if_oo_adt_classrun~main.

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************
TRY.
connection = NEW #(
i_carrier_id = 'LH'
i_connection_id = '0400'
).

* connection->set_attributes(
* EXPORTING
* i_carrier_id = 'LH'
* i_connection_id = '0400'
* ).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Second instance
**********************************************************************
TRY.
connection = NEW #(
i_carrier_id = 'AA'
i_connection_id = '0017'
).
APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Third instance
**********************************************************************

166 © Copyright. All rights reserved.


Lesson: Using Encapsulation To Ensure Consistency

TRY.
connection = NEW #(
i_carrier_id = 'SQ'
i_connection_id = '0001'
).
APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Output
**********************************************************************
LOOP AT connections INTO connection.
out->write( connection->get_output( ) ).
ENDLOOP.
ENDMETHOD.

6. Activate the class. Execute it and debug the instantiation.


a) Press Ctrl + F3 to activate the class.

b) Press F9 to run the class.

© Copyright. All rights reserved. 167


Unit 3: Local Classes

LESSON SUMMARY
You should now be able to:
● Explain Encapsulation
● Define and Use Constructors

168 © Copyright. All rights reserved.


Unit 3

Learning Assessment

1. In which order do you define the visibility sections of a class?


Choose the correct answer.

X A PUBLIC SECTION. PROTECTED SECTION. PRIVATE SECTION.

X B PRIVATE SECTION. PROTECTED SECTION. PUBLIC SECTION.

X C It doesn't matter.

2. You have defined a class containing instance attributes and static attributes. You have
also declared a reference variable but not yet created a new instance of the class. Which
components of the class can you access at this point, and how?
Choose the correct answers.

X A Instance components using the reference variable.

X B Instance components using the name of the class.

X C Static components using the reference variable.

X D Static components using the name of the class.

3. You have declared two reference variables, ref1 and ref2. ref1 points to an object. You now
execute the statement ref2 = ref1. What happens?
Choose the correct answer.

X A The ABAP system creates a copy of the object to which ref1 is pointing and assigns
its address to ref2. There are now two objects.

X B The ABAP system assigns the address of the object to which ref1is pointing to
reference variable ref2. There is only one object.

© Copyright. All rights reserved. 169


Unit 3: Learning Assessment

4. A class my_class contains the public static method my_method. What is the correct code
to call this method?
Choose the correct answer.

X A my_class->my_method().

X B my_class=>my_method().

X C my_class->my_method( ).

X D my_class=>my_method( ).

5. A functional method must have


Choose the correct answer.

X A Exactly one importing parameter

X B Exactly one exporting parameter

X C No changing parameters

X D Exactly one returning parameter

6. Your class contains a public instance attribute attr. How could you ensure that its value
can only be changed within the class?
Choose the correct answers.

X A Make it a private attribute.

X B Convert it into a constant.

X C Leave it in the public section but use the READ-ONLY addition.

X D Move it to a different local class.

7. Which of the following signature elements may an instance constructor have?


Choose the correct answers.

X A Importing parameters

X B Exporting parameters

X C Changing parameters

X D Exceptions

170 © Copyright. All rights reserved.


Unit 3: Learning Assessment

8. The static constructor is executed when the class is addressed for the first time. When
might this be?
Choose the correct answers.

X A At the beginning of the program.

X B When you call a static method of the class.

X C When you instantiate the class.

© Copyright. All rights reserved. 171


Unit 3: Learning Assessment

172 © Copyright. All rights reserved.


UNIT 4 Data Modelling and ABAP SQL

Lesson 1
Investigating a Table Definition 175

Lesson 2
Implementing Basic SELECT Statements 179

Lesson 3
Working with CDS View 187
Exercise 8: Analyze and Use a CDS View Entity 193

UNIT OBJECTIVES

● Investigate a table definition


● Describe basic features of ABAP SQL
● Read single values from the database
● Analyze a CDS view definition
● Read data using a CDS view

© Copyright. All rights reserved. 173


Unit 4: Data Modelling and ABAP SQL

174 © Copyright. All rights reserved.


Unit 4
Lesson 1
Investigating a Table Definition

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Investigate a table definition

Investigating the Definition of Database Table


Every ABAP system runs on a relational database management system (DBMS). Originally,
ABAP supported different database management systems from different vendors. Therefore
the definition of database objects like tables and views is done in a database independent
way.

Note:

Newer ABAP releases only support SAP HANA as database. The ABAP Environment on SAP
BTP only runs on SAP HANA.

Figure 98: Database Table Definition

In a relational database, information is stored in two-dimensional tables, in which each row


represents one data record whose contents are split up into columns. The database is called a
relational database, as there are also relations between tables. For example, the table in the
figure contains an airline code. In the database table, there would be a relationship to a further
table containing the information that AA stands for American Airlines, JL for Japanese Airline,
LH for Lufthansa, and so on.

© Copyright. All rights reserved. 175


Unit 4: Data Modelling and ABAP SQL

A sequence of columns at the beginning of each database table forms its key. The key is a
combination of values that ensures that each row in the table can be identified uniquely.
In SAP systems, database table definitions are development objects, and as such, are cross-
client. However, the vast majority of tables contain business data, which is client-specific. To
keep the data separate, client-specific tables have a client field (often named CLIENT or
MANDT) as their first key field. The database of SAP accesses statements using ABAP SQL to
ensure that a statement only manipulates data from the current client.

Database Table Definitions

Figure 99: Database Tables in ABAP Development Tools

ADT provides a dedicated editor for database table definitions.


Let's look at the different parts of the table definition.

Animation
For more information on this topic please view the animation in the lesson
Investigating a Table Definition in your online course.

The main part of the definition consists of a DEFINE TABLE statement with the name of the
table. This is followed by the list of table fields in a pair of curly brackets ( { , } ); each field with
a type that is described by a data element. A subset of fields at the beginning of the list
defines the key, which identifies each record uniquely.
Several additional code lines before the DEFINE TABLE statement specify additional
properties of the database table, among them a label.

176 © Copyright. All rights reserved.


Lesson: Investigating a Table Definition

Data Preview for Database Tables

Figure 100: Data Preview for Database Tables

You can use the Data Preview tool to display and analyze the content of a database table. To
open the Data Preview for a given table, right-click anywhere in the table definition and choose
Open With → Data Preview. Alternatively, place the cursor anywhere in the database table
definition and press F8.
The tool displays the data stored in the database table. Some of the most important functions
are the following:
The tool displays the data stored in the database table. Some of the most important functions
are shown here.

Select Columns
For tables with many columns, you can adjust the columns you want to display.
Change Column Sequence
You can change the column sequence by dragging and dropping a column header to
another position.
Apply Sorting
You can apply a sorting by left-clicking on a column header.
Add Filter
For tables with many rows you can filter the data by choosing Add Filter.
Refresh Display
Choose the Refresh button to reload the data.
Number of Entries
Choose Number of Entries if you are only interested in the number of rows that meet your
filter conditions. Without filters, the total number of entries is displayed.

Animation
For more information on this topic please view the animation in the lesson
Investigating a Table Definition in your online course.

© Copyright. All rights reserved. 177


Unit 4: Data Modelling and ABAP SQL

LESSON SUMMARY
You should now be able to:
● Investigate a table definition

178 © Copyright. All rights reserved.


Unit 4
Lesson 2
Implementing Basic SELECT Statements

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Describe basic features of ABAP SQL
● Read single values from the database

Basic ABAP SQL Syntax


Structured Query Language (SQL)

Figure 101: Structured Query Language (SQL)

All relational database systems use a variant of Structured Query Language (SQL) to allow
you to work with them. Standard SQL consists of three main components:

Data Manipulation Language (DML)


DML comprises of the statements that you need to work with information in database
tables. These are INSERT, for adding new records, SELECT, for reading data, UPDATE, to
change existing records, and DELETE, to delete table contents. These statements are
reflected in ABAP in the form of ABAP SQL.
Data Definition Language (DDL)
Data Definition Language provides you with commands that enable you to create and
delete database tables and other database artifacts such as schemata, table indexes, and
views. In an SAP system, you perform these tasks using dedicated editors of ADT, not
with ABAP programs. One example is the editor for database table definitions we saw
earlier.
Data Control Language (DCL)

© Copyright. All rights reserved. 179


Unit 4: Data Modelling and ABAP SQL

Data Control Language is used in SQL to restrict access to data in the database for a
particular user. It is not used in its classic form in ABAP, since the users at database level
do not correspond one-to-one with the end users. Consequently, ABAP has its own
authorization concept.

Animation
For more information on this topic please view the animation in the lesson
Implementing Basic SELECT Statements in your online course.

ABAP SQL Architecture

Figure 102: ABAP SQL Architecture

In the past, SAP systems had to support a range of database platforms, and each platform
had a slightly different implementation of the SQL standard. This meant that each platform
needed slightly different commands to achieve a particular task. To avoid the ABAP code
being database-specific, SAP invented ABAP SQL - or Open SQL as it was called originally.

Note:
The name change from Open SQL and ABAP SQL also illustrates that as off
release 7.53 ABAP only supports SAP HANA as DBMS.

ABAP SQL is an abstract set of SQL commands implemented at ABAP level and integrated
into the ABAP language. At runtime, ABAP SQL is translated into a variant of SQL that the
database understands. This variant is called Native SQL to distinguish it from ABAP SQL, the
SQL variant that is integrated into ABAP. The translation from ABAP SQL to Native SQL takes
place in the database interface, a component of the ABAP system that consists of a general
part and a database-specific library.
Even though newer ABAP releases only support SAP HANA as DBMS, SAP has still retained
the concept of ABAP SQL and the database interface. This is because of the following
reasons:

180 © Copyright. All rights reserved.


Lesson: Implementing Basic SELECT Statements

Architecture compatibility
ABAP SQL and the database interface are an integral part of the system architecture.
Code compatibility
ABAP SQL coding from previous SAP products (including customer-specific
development) should run free of side-effects in the modern, SAP-HANA-only ABAP
environments.
Tasks of the Database Interface
The database interface does not just translate statements; it is also responsible for ABAP
specific tasks like, for example, automatic client-handling.

Reading a Single Record from the Database


The SELECT Statement in ABAP

Figure 103: The SELECT Statement in ABAP

To read data from the database, you use the SELECT statement.
When you write a SELECT statement in ABAP SQL, the syntax check compares what you have
written with the definition of the tables and views. If you try to address tables, views, or fields
that do not exist, a syntax error occurs.
The basic syntax of the SELECT statement contains several sections, called clauses, and
always follows the pattern in the figure, The SELECT Statement in ABAP. The most important
clauses of a SELECT statement are as follows:

FROM
In the FROM clause of the SELECT statement, you specify the data source from which
you want to read. This can be either be a database table or a view. Special SQL
techniques allow you to combine data from multiple sources in the same SELECT
statement.

FIELDS
In the FIELDS clause of the SELECT statement, you list the columns of the database table
that you want to read. The columns in the list must be separated by commas. If you want
to read the entire table line, you can specify FIELDS * instead of a column list. Be aware,
however, that this can cause the database considerably more work than just reading the
columns you need.
WHERE

© Copyright. All rights reserved. 181


Unit 4: Data Modelling and ABAP SQL

In the WHERE clause, you can specify a condition that describes which rows of the table
will be read. For example, the condition WHERE carrier_id = 'LH' means that only those
rows will be read (in which the column CARRIER_D contains the value LH).
The WHERE clause can contain multiple conditions linked with the AND and OR
operators. For example, WHERE carrier_id = 'LH' and connection_id = '0400' would
return the data of flight connection LH 0400. You can also negate conditions using NOT.
The WHERE clause is the only clause that is optional. Be aware, however, that without a
WHERE clause you read all data from the table, or if the table has a client field - all data
that belongs to the logon client of the user. SELECTs without a WHERE clause can cause
serious performance problems and should be avoided.
INTO
The INTO clause specifies the variable or variables in the ABAP program into which the
data should be placed. This is normally a structure, or an internal table, and should ideally
have the same sequence of components as the column list in the FIELDS clause.

Note:
You will see other forms of SQL syntax in ABAP. These are older and have been
retained to ensure compatibility. You should get used to using the modern syntax,
as it provides far more functions and features than the old form.

The syntax of the SELECT statement is explained here. You will also see some examples of
the SELECT statement.

Animation
For more information on this topic please view the animation in the lesson
Implementing Basic SELECT Statements in your online course.

Figure 104: Example 1: Reading Single Field of Single Record

The figure, Example 1: Reading Single Field of Single Record, illustrates a SELECT statement
that reads a single value from the database. The FROM clause tells us that the statement
reads from database table /DMO/CONNECTION. The option, SINGLE, after the keyword,

182 © Copyright. All rights reserved.


Lesson: Implementing Basic SELECT Statements

SELECT, indicates that only one row (a single record) is read. This row is identified in the
WHERE clause by providing key filter values for key fields carrier_id and connection_id. Keep
in mind, that the database interface will add a filter on the remaining key field client.
The FIELDS clause lists only one column of the table: column AIRPORT_FROM_ID.
The INTO clause has to match the rest of the statement. In our example, this specifies the
variable airport_from_id as the target object, a scalar data object of identical type as table
field, airport_from_id.

Note:
The at sign (@) identifies airport_from_id as the name of an ABAP data object. It is
mandatory for all variables and constants that you use in an ABAP SQL statement.
It is needed to avoid ambiguities if, for example, a data object and table field have
the same name.

Figure 105: Example 2: Reading Several Fields of Single Record

The figure, Example 2: Reading Several Fields of Single Record, illustrates a SELECT
statement that reads two values from the same record of the database.
This time, the FIELDS clause lists two columns of the table; column AIRPORT_FROM_ID and
column AIRPORT_TO_ID.
To match this, the INTO clause specifies the variables airport_from_id and airport_to_id as
the target objects. They are separated by a comma and surrounded by pair of brackets to
make it clear that together they form the target of the SELECT statement.

© Copyright. All rights reserved. 183


Unit 4: Data Modelling and ABAP SQL

Figure 106: What Happens If There Is No Result?

When you implement a SELECT statement you always have to take into account that there
could be no result, either because the database table does not contain any data at all or
because it does not contain any rows that fulfill the conditions in the WHERE clause. In the
example from the figure above, the database table does not contain a row with carrier_id =
'XX' and connection_id = '1234'.
ABAP SQL use system field SY-SUBRC to indicate a successful or unsuccessful execution of a
statement. System field SY-SUBRC is of type integer. Initial value 0 always indicates a
successful execution. If, after a SELECT statement, SY-SUBRC contains the value 4, this
indicates that the database returned an empty result.

Note:
If the database returns an empty result, ABAP SQL does NOT touch the target
variable after INTO!
In particular, the target variable is not initialized in case of an error.

Figure 107: Handling Empty Results

It is recommended that you evaluate the content of system field sy-subrc immediately after
each SELECT statement.

184 © Copyright. All rights reserved.


Lesson: Implementing Basic SELECT Statements

Try It Out: SELECT Examples


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

DATA airport_from_id TYPE /DMO/airport_from_id.


DATA airport_to_id TYPE /DMO/airport_to_id.

DATA airports TYPE TABLE OF /DMO/airport_from_id.

* Example 1: Single field from Single Record


**********************************************************************
SELECT SINGLE
FROM /dmo/connection
FIELDS airport_from_id
WHERE carrier_id = 'LH'
AND connection_id = '0400'
INTO @airport_from_id.

out->write( `----------` ).
out->write( `Example 1:` ).

out->write( |Flight LH 400 departs from { airport_from_id }.| ).

* Example 2: Multiple Fields from Single Record


**********************************************************************
SELECT SINGLE
FROM /dmo/connection
FIELDS airport_from_id, airport_to_id
WHERE carrier_id = 'LH'
AND connection_id = '0400'
INTO ( @airport_from_id, @airport_to_id ).

out->write( `----------` ).
out->write( `Example 2:` ).

out->write( |Flight LH 400 flies from { airport_from_id } to


{ airport_to_id }| ).

* Example 3: Empty Result and sy-subrc


**********************************************************************
SELECT SINGLE
FROM /dmo/connection
FIELDS airport_from_id
WHERE carrier_id = 'XX'
AND connection_id = '1234'
INTO @airport_from_id.

IF sy-subrc = 0.

out->write( `----------` ).
out->write( `Example 3:` ).
out->write( |Flight XX 1234 departs from
{ airport_from_id }.| ).

ELSE.

out->write( `----------` ).
out->write( `Example 3:` ).

© Copyright. All rights reserved. 185


Unit 4: Data Modelling and ABAP SQL

out->write( |There is no flight XX 1234, but still


airport_from_id = { airport_from_id }!| ).

ENDIF.

3. Press CTRL + F3 to activate the class and F9 to execute it as a console app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

LESSON SUMMARY
You should now be able to:
● Describe basic features of ABAP SQL
● Read single values from the database

186 © Copyright. All rights reserved.


Unit 4
Lesson 3
Working with CDS View

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Analyze a CDS view definition
● Read data using a CDS view

Analyze CDS View


View Definitions in ABAP Core Data Services (ABAP CDS)
ABAP Code Data Services, or ABAP CDS for short, is an infrastructure for defining and
consuming semantically rich data models in ABAP. They use a CDS DDL to define CDS
entities that implement a semantic data model. The most important CDS modeling entities
are CDS View entities.

Figure 108: View Definitions in ABAP Core Data Services (ABAP CDS)

The CDS View definition contains re-usable SQL logic; sometimes as simple as a projection of
table fields and sometimes more sophisticated with calculations, aggregations, joins, unions,
and so on.
A CDS View definition can contain associations to reflect the relations of the data model.
Consumers of the view can use the associations to retrieve related data.
Finally, annotations are used to semantically enrich the view definition. This metadata is
evaluated by frameworks that build on top of CDS View definitions. One such framework is the
ABAP RESTful Application programming model (ABAP RAP), for which we will discuss an
example later in this course.
Let's watch examples of CDS view definitions.

© Copyright. All rights reserved. 187


Unit 4: Data Modelling and ABAP SQL

Animation
For more information on this topic please view the animation in the lesson
Working with CDS View in your online course.

Figure 109: Example: CDS View Definition - SQL logic

CDS View definitions are contained in repository objects of type Data Definition. Let us now
have a look at the source code of data definition /DMO/I_CONNECTION.
The main part is the DEFINE VIEW ENTITY statement. It contains the name of the CDS View
entity and, after keyword FROM, the data source. In our example, the name of the view entity
is /DMO/I_Connection and the data source is database table /dmo/connection. Optional
addition AS, defines an alias name Connection to address the data source inside the View
definition.

Note:
The source of a CDS View entity could also be another CDS View.

A pair of curly brackets contains the list of view elements. In our example, the view elements
are fields of database table /dmo/connection. Keyword Key in front of the first two elements
defines them as key fields of the CDS View entity. Optional addition AS defines an alias name
for each view element.

188 © Copyright. All rights reserved.


Lesson: Working with CDS View

Figure 110: Example: CDS View Definition - Association

Addition association defines a relation to another CDS view entity. In our example, the related
is CDS view entity /DMO/I_Carrier and the name of the association is _Airline.
This association becomes available for consumers of the view by adding it to the element list.
This is referred to as exposing the association.

Figure 111: Example: CDS View Definition - Annotations

Annotations start with the at sign (@) and they are used to semantically enrich the view
definition for consumers. Annotations before the view definition are called entity annotations.
Entity annotations are used to define metadata for the view entity as a whole. Annotations
between the curly brackets are called element annotations. Element annotations are used to
define metadata for the different elements of the view.

© Copyright. All rights reserved. 189


Unit 4: Data Modelling and ABAP SQL

Figure 112: Data Preview for CDS View Entity

You already learned how to use the Data Preview tool to display and analyze the content of a
database table. This tool is also available for CDS view entities.
To open the Data Preview for a given CDS entity, right-click anywhere in the data definition
and choose Open With > Data Preview. Alternatively, place the cursor anywhere in the
database table definition and press Ctrl + F8.
The tool displays the data returned by the CDS entity. The same functions are available to
sort or filter the data and adjust the display.
If the view definition contains one or more associations, you can use them to display related
data. To do so, proceed in the following manner:

1. Right-click on a row in the display.

2. From the context menu, choose Follow Association.

3. From the list of available associations, choose the one in which you are interested.

Figure 113: Finding CDS Views Based on a Database Table

If you want to find all CDS Views with a certain database table as a source, you can utilize the
Where-used List tool of ADT. To use this tool, proceed as follows:

1. Open the definition of the database table.

190 © Copyright. All rights reserved.


Lesson: Working with CDS View

2. Right-click anywhere in the source code and choose Get Where-used List from the context
menu. Alternatively, you can press Ctrl + Shift + G, or choose the button from the toolbar
with the same symbol.

3. The Search view displays a list of all development objects that directly use the database
table.

Figure 114: Applying Filters to the Where-used List

You can apply filters to the Where-used List if, for example, you are only interested in objects
from certain packages or objects of the specific object type. The example illustrates how to
filter for CDS views that use the table.

Reading Data Using a CDS View

Figure 115: Example: Reading Data From a CDS View Entity

When you implement a SELECT statement in ABAP, you can use a CDS view entity as the data
source instead of reading from the database table directly. This has several advantages.
● Re-use of the SQL logic contained in the CDS view
● Concise, easy-to-read reading of related data using the associations
● Sometimes the names of views and view elements are better readable than the more
technical names of database tables and table fields

The SELECT statement in the example uses CDS view entity /DMO/I_Connection as a data
source.

© Copyright. All rights reserved. 191


Unit 4: Data Modelling and ABAP SQL

Note:
Note that the names used in the FIELDS clause and WHERE conditions are the
alias names of the view elements.

The third element in the FIELDS clause makes use of exposed association _Airline. It reads
element name from the associated CDS view entity /DMO/I_Airline. This kind of element is
called a path expression. The backslash (\) is a mandatory prefix for association names.

192 © Copyright. All rights reserved.


Unit 4
Exercise 8
Analyze and Use a CDS View Entity

Task 1: Preparation

1. If you finished the previous exercise Use Private Attributes and Constructors, create a
copy of your global class ZCL_##_CONSTRUCTORS, and name the copy ZCL_##_CDS,
where ## is your group number. Then skip the rest of this task.

2. If you did not finish the previous exercise, create a new global class ZCL_##_CDS, where
## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'LH'
i_connection_id = '0400'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Second instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'AA'
i_connection_id = '0017'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Third instance
**********************************************************************

TRY.

© Copyright. All rights reserved. 193


Unit 4: Data Modelling and ABAP SQL

connection = NEW #(
i_carrier_id = 'SQ'
i_connection_id = '0001'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Output
**********************************************************************

LOOP AT connections INTO connection.

out->write( connection->get_output( ) ).

ENDLOOP.

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

CLASS-DATA conn_counter TYPE i.

METHODS constructor
IMPORTING
i_connection_id TYPE /dmo/connection_id
i_carrier_id TYPE /dmo/carrier_id
RAISING
cx_ABAP_INVALID_VALUE .

METHODS get_output
RETURNING
VALUE(r_output) TYPE string_table.

PROTECTED SECTION.
PRIVATE SECTION.
DATA carrier_id TYPE /dmo/carrier_id.
DATA connection_id TYPE /dmo/connection_id.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD constructor.
IF carrier_id IS INITIAL OR connection_id IS INITIAL.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

me->connection_id = i_connection_id.
me->carrier_id = i_carrier_id.

conn_counter = conn_counter + 1.

ENDMETHOD.

METHOD get_output.

APPEND |------------------------------| TO r_output.

194 © Copyright. All rights reserved.


Lesson: Working with CDS View

APPEND |Carrier: { carrier_id }| TO r_output.


APPEND |Connection: { connection_id }| TO r_output.

ENDMETHOD.

ENDCLASS.

Task 2: Declare Additional Attributes


Extend local class lcl_connection with private instance attributes airport_from_id,
airport_to_id, and carrier_name. Add some output for the new attributes to the
implementation of method get_output( ).

Note:
The new attributes are not filled, yet. In order to fill them we will add a SELECT
statement to the constructor( ) in one of the next tasks of this exercise.

1. Switch to the local class lcl_connection.

2. Add the following private attributes to the class definition:

Table 2: Attributes
Attribute Name Scope Data Type
airport_from_id instance /DMO/AIRPORT_FROM_ID

airport_to_id instance /DMO/AIRPORT_TO_ID

carrier_name instance /DMO/CARRIER_NAME

3. Extend the implementation of method get_output( ). Append more string templates to


returning parameter r_output. Embed the new attributes as expressions into the string
templates.

4. Activate the class. Execute it and analyze the console output.

Task 3: Analyze CDS View Entity


Analyze the definition of CDS View Entity /DMO/I_Connection.

1. Open the development object that contains the definition of CDS View Entity /DMO/
I_Connection.

2. Open the Tooltip Description for the data source of the CDS View entity. Find out the
names of the fields that are typed with /dmo/airport_from_id and /dmo/
airport_to_id.

3. Analyze the element list of the CDS view entity. Find out the alias names for fields
airport_from_id and airport_to_id.

4. Open the Tooltip Description for the target of association _Airline. Find out the alias
name of the field that is typed with /dmo/carrier_id.

Task 4: Use CDS View Entity


In method constructor( ) of local class lcl_connection, implement a SELECT
statements that reads values for the new attributes from CDS view entity /DMO/
I_Connection.

© Copyright. All rights reserved. 195


Unit 4: Data Modelling and ABAP SQL

1. Return to local class lcl_connection in your global class ZCL_##_CDS.

2. Navigate to the implementation of method constructor( ).

3. After statement ENDIF. add a SELECT statement that reads a single record from CDS
view entity /DMO/I_Connection.

4. Implement the FIELDS clause. Read view elements DepartureAirport and


DestinationAirport. Also read view element Name from the target of association
_Airline.

Hint:
Use auto-completion (Ctrl + Space) to enter the names.

5. Implement the WHERE clause. Restrict the key elements of CDS view entity with the
values of importing parameters i_carrier_id and i_connection_id. Do not forget to
escape the parameters with prefix @.

Hint:
Use auto-completion (Ctrl + Space) to enter the element names and
parameter names.

6. Implement the INTO clause. Store the SELECT result in attributes airport_from_id,
airport_to_id, and airline_name. Do not forget to escape the attributes with prefix
@.

Hint:
Use auto-completion (Ctrl + Space) to enter the attribute names.

7. Implement error handling after the SELECT statement. Check the content of system field
sy-subrc. If it does not equal Zero, raise exception CX_ABAP_INVALID_VALUE.

8. Activate the class. Execute it and analyze the console output. Check that the output for
the new attributes displays data.

196 © Copyright. All rights reserved.


Unit 4
Solution 8
Analyze and Use a CDS View Entity

Task 1: Preparation

1. If you finished the previous exercise Use Private Attributes and Constructors, create a
copy of your global class ZCL_##_CONSTRUCTORS, and name the copy ZCL_##_CDS,
where ## is your group number. Then skip the rest of this task.
a) In the Project Explorer view on the left, expand your package.

b) Expand node Source Code Library → Classes

c) Right-click the name of the class you want to copy and choose Duplicate.

d) In the Name field, enter the name ZCL_##_CDS, where ## is your group number.

e) Choose Next.

f) Select your transport request and choose Finish.

2. If you did not finish the previous exercise, create a new global class ZCL_##_CDS, where
## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_CDS, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'LH'
i_connection_id = '0400'
).

© Copyright. All rights reserved. 197


Unit 4: Data Modelling and ABAP SQL

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Second instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'AA'
i_connection_id = '0017'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Third instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'SQ'
i_connection_id = '0001'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Output
**********************************************************************

LOOP AT connections INTO connection.

out->write( connection->get_output( ) ).

ENDLOOP.

a) Navigate to the Global Class tab and insert the source code between METHOD
if_oo_adt_classrun~main. and ENDMETHOD..

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

CLASS-DATA conn_counter TYPE i.

METHODS constructor
IMPORTING
i_connection_id TYPE /dmo/connection_id
i_carrier_id TYPE /dmo/carrier_id
RAISING
cx_ABAP_INVALID_VALUE .

198 © Copyright. All rights reserved.


Lesson: Working with CDS View

METHODS get_output
RETURNING
VALUE(r_output) TYPE string_table.

PROTECTED SECTION.
PRIVATE SECTION.
DATA carrier_id TYPE /dmo/carrier_id.
DATA connection_id TYPE /dmo/connection_id.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD constructor.
IF carrier_id IS INITIAL OR connection_id IS INITIAL.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

me->connection_id = i_connection_id.
me->carrier_id = i_carrier_id.

conn_counter = conn_counter + 1.

ENDMETHOD.

METHOD get_output.

APPEND |------------------------------| TO r_output.


APPEND |Carrier: { carrier_id }| TO r_output.
APPEND |Connection: { connection_id }| TO r_output.

ENDMETHOD.

ENDCLASS.

a) Navigate to the Local Types tab and insert the source code.

Task 2: Declare Additional Attributes


Extend local class lcl_connection with private instance attributes airport_from_id,
airport_to_id, and carrier_name. Add some output for the new attributes to the
implementation of method get_output( ).

Note:
The new attributes are not filled, yet. In order to fill them we will add a SELECT
statement to the constructor( ) in one of the next tasks of this exercise.

1. Switch to the local class lcl_connection.


a) In the global class, choose Local Types.

2. Add the following private attributes to the class definition:

Table 2: Attributes
Attribute Name Scope Data Type
airport_from_id instance /DMO/AIRPORT_FROM_ID

© Copyright. All rights reserved. 199


Unit 4: Data Modelling and ABAP SQL

Attribute Name Scope Data Type


airport_to_id instance /DMO/AIRPORT_TO_ID

carrier_name instance /DMO/CARRIER_NAME

a) After line PRIVATE SECTION. and before line ENDCLASS., add the following three
statements:

DATA airport_from_id TYPE /dmo/airport_from_id.


DATA airport_to_id TYPE /dmo/airport_to_id.

DATA carrier_name TYPE /dmo/carrier_name.

3. Extend the implementation of method get_output( ). Append more string templates to


returning parameter r_output. Embed the new attributes as expressions into the string
templates.
a) Navigate to the implementation of method get_output( ).

b) At the end of the method, add the following two statements:

APPEND |Departure: { airport_from_id }| TO r_output.


APPEND |Destination: { airport_to_id }| TO r_output.

c) Replace statement APPEND |Carrier: { carrier_id }| TO


r_output. with the following statement:

APPEND |Carrier: { carrier_id } { carrier_name }| TO r_output.

4. Activate the class. Execute it and analyze the console output.


a) Press Ctrl + F3 to activate the class.

b) Press F9 to run the class.

Task 3: Analyze CDS View Entity


Analyze the definition of CDS View Entity /DMO/I_Connection.

1. Open the development object that contains the definition of CDS View Entity /DMO/
I_Connection.
a) From the toolbar of ADT, choose Open ABAP Development Object or press Ctrl +
Shift + A.

b) In the input field, enter /DMO/I_Con as search string.

c) In the list of matching items, click on /DMO/I_CONNECTION (Data Definition) and


choose OK.

2. Open the Tooltip Description for the data source of the CDS View entity. Find out the
names of the fields that are typed with /dmo/airport_from_id and /dmo/
airport_to_id.
a) Click on /dmo/connection after keyword FROM and press F2 to show the tooltip
description.

b) The names of the fields are airport_from_id and airport_to_id.

200 © Copyright. All rights reserved.


Lesson: Working with CDS View

3. Analyze the element list of the CDS view entity. Find out the alias names for fields
airport_from_id and airport_to_id.
a) Navigate to the comma-seperated list between the pair of curly brackets ( { } ).

b) The alias names are DepartureAirport and DestinationAirport.

4. Open the Tooltip Description for the target of association _Airline. Find out the alias
name of the field that is typed with /dmo/carrier_id.
a) Click on /DMO/I_Carrier after association [1..1] to and press F2 to show the
tooltip description.

b) Field Name is typed with /dmo/carrier_name.

Task 4: Use CDS View Entity


In method constructor( ) of local class lcl_connection, implement a SELECT
statements that reads values for the new attributes from CDS view entity /DMO/
I_Connection.

1. Return to local class lcl_connection in your global class ZCL_##_CDS.


a) In the editor view of Eclipse, open tab ZCL_##_CDS.

b) In the global class, choose Local Types.

2. Navigate to the implementation of method constructor( ).


a) Search for code line METHOD constructor..

3. After statement ENDIF. add a SELECT statement that reads a single record from CDS
view entity /DMO/I_Connection.
a) After ENDIF., add the following code:
SELECT SINGLE
FROM /DMO/I_Connection

4. Implement the FIELDS clause. Read view elements DepartureAirport and


DestinationAirport. Also read view element Name from the target of association
_Airline.

Hint:
Use auto-completion (Ctrl + Space) to enter the names.

a) After FROM /DMO/I_Connection enter FIELDS.

b) After a blank, press Ctrl + Space and choose DepartureAirport.

c) After a comma and a blank press Ctrl + Space again and choose
DestinationAirport.

d) After a comma and a blank, type in a backslash (\) , press Ctrl + Space and choose
_Airline.

e) Immediately after _Airline, type in a dash sign (-) , press Ctrl + Space and
choose Name.

© Copyright. All rights reserved. 201


Unit 4: Data Modelling and ABAP SQL

f) The complete FIELDS clause should look like this:

FIELDS DepartureAirport, DestinationAirport, \_Airline-Name

5. Implement the WHERE clause. Restrict the key elements of CDS view entity with the
values of importing parameters i_carrier_id and i_connection_id. Do not forget to
escape the parameters with prefix @.

Hint:
Use auto-completion (Ctrl + Space) to enter the element names and
parameter names.

a) Add the following code after the FIELDS clause:

WHERE AirlineID = @i_carrier_id


AND ConnectionID = @i_connection_id

6. Implement the INTO clause. Store the SELECT result in attributes airport_from_id,
airport_to_id, and airline_name. Do not forget to escape the attributes with prefix
@.

Hint:
Use auto-completion (Ctrl + Space) to enter the attribute names.

a) Add the following code after the WHERE clause:

INTO ( @airport_from_id, @airport_to_id, @carrier_name ).

b) The complete SELECT statement should look like this:

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport, DestinationAirport, \_Airline-Name
WHERE AirlineID = @i_carrier_id
AND ConnectionID = @i_connection_id
INTO ( @airport_from_id, @airport_to_id, @carrier_name ).

7. Implement error handling after the SELECT statement. Check the content of system field
sy-subrc. If it does not equal Zero, raise exception CX_ABAP_INVALID_VALUE.
a) Add the following code after the SELECT statement:

IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

8. Activate the class. Execute it and analyze the console output. Check that the output for
the new attributes displays data.
a) Press Ctrl + F3 to activate the class.

b) Press F9 to run the class.

202 © Copyright. All rights reserved.


Lesson: Working with CDS View

LESSON SUMMARY
You should now be able to:
● Analyze a CDS view definition
● Read data using a CDS view

© Copyright. All rights reserved. 203


Unit 4: Data Modelling and ABAP SQL

204 © Copyright. All rights reserved.


Unit 4

Learning Assessment

1. Which part of SQL is represented by ABAP SQL?


Choose the correct answer.

X A Data Control Language

X B Data Definition Language

X C Data Manipulation Language

2. What is the correct sequence of clauses in the SELECT SINGLE statement?


Choose the correct answer.

X A SELECT SINGLE FIELDS... FROM... INTO... WHERE...

X B SELECT SINGLE FROM... FIELDS... WHERE... INTO

X C SELECT SINGLE FROM... FIELDS... INTO... WHERE...

X D You can write the clauses in any sequence.

3. Which of the following are valid data sources for a CDS view entity?
Choose the correct answers.

X A An internal table

X B A database table

X C Another CDS view entity

X D A structure

4. You are writing a SELECT statement that reads data using a CDS view entity. In the field
list, you want to read a field from an associated table. What do you use?
Choose the correct answer.

X A A logical expression

X B A path expression

X C A regular expression

© Copyright. All rights reserved. 205


Unit 4: Learning Assessment

206 © Copyright. All rights reserved.


UNIT 5 Structured Data Objects

Lesson 1
Declaring a Structured Data Object 209

Lesson 2
Working with Structured Data Objects 216
Exercise 9: Use a Structured Data Object 231

UNIT OBJECTIVES

● Declare structured data object


● Work with structured data objects
● Use structured data objects in ABAP SQL

© Copyright. All rights reserved. 207


Unit 5: Structured Data Objects

208 © Copyright. All rights reserved.


Unit 5
Lesson 1
Declaring a Structured Data Object

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Declare structured data object

Structured Data Objects

Figure 116: The Story So Far - Simple Variables

Up until now, you have been using simple variables, each of which can store a single piece of
information. Here, for example, there are two variables, one for the departure airport, the
other for the arrival airport.
When you read a record from the database you need to hold all of this information together.
The two variables in the example are completely independent of one another, and are
therefore not suitable for storing different pieces of information that belong together.
In ABAP, the solution is to use a structured variable, or a structure, for short.

© Copyright. All rights reserved. 209


Unit 5: Structured Data Objects

Figure 117: Structured Variables

A structure is a variable ABAP data object with a name and a structured type.
In the example, data object connection_full is such a structure. It is subdivided into eight
components, each of which also has a name and a type. You can address both the structure
as a whole and the individual components. Importantly, you can use each component in
exactly the same way that you would use a standalone simple variable.
There are various possibilities to declare a structure. You can define structured types with
keyword TYPES or use a repository object of type Structure. The definitions of views and
database tables can also serve as structured types. The example uses CDS View /DMO/
I_Connection as a structured type.

Figure 118: Structured Variables in the Debugger Perspective

In the debugger perspective, there are two ways to analyze the structure and content of a
structured variable:

210 © Copyright. All rights reserved.


Lesson: Declaring a Structured Data Object

Animation
For more information on this topic please view the animation in the lesson
Declaring a Structured Data Object in your online course.

Variable Preview (Mouse Over)


Set the focus on the Source Code Editor and place the pointer on a variable name. After a
moment a dialog window opens with details on the structure and content of the data
object.
Display in the Variables View (Double-Click)
To display the variable in the Variables view, either enter the variable name under <enter
variable> or double-click the variable name somewhere in the source code editor. Expand
the node with the structure name to see the list of components

Structured Data Types

Figure 119: Global Structured Types

A global structure type is a repository object that can be used as data type anywhere in the
system. In the example, structured type SYMSG is used to declare variable message.
When you press the F2 key to display the details of this data type you can see that this is a
structure type consisting of seven components. You can also see the names, technical types
and descriptions of the components.
When you press the F3 key to navigate to the definition of the type, a new view opens with the
ADT editor for global structured types.
The definition of a global structure type is very similar to the definition of a database table.
The main part of the definition consists of a DEFINE STRUCTURE statement with the name of
the structure type. This is followed by the list of structure components in a pair of curly
brackets ( { , } ); each component with a component type. Component types are often
described by data elements, but it is also possible to use structure types as component types.
Structures with structured components are referred to as Nested Structures.

© Copyright. All rights reserved. 211


Unit 5: Structured Data Objects

Additional code lines before the DEFINE STRUCTURE statement specify additional properties
of the structure type, among them a label.

Figure 120: Defining Structured Types Locally

You can also define structured types in an ABAP program using the TYPES statement. The
structure definition begins with the statement TYPES BEGIN OF <structure type name> and
ends with TYPES END OF <structure type name>. In between, you name each component and
specify its type in an additional TYPES statement.
A compact form uses keyword TYPES only once, followed by a colon( : ). The BEGIN OF
addition, the END OF addition and the component definitions in between are then separated
by commas.
This is referred to as chain statement.

Note:
In the past, chain statements were used a lot in ABAP. Nowadays they are only
recommended to combine statements that belong closely together.

Figure 121: Example: Local Structured Type

212 © Copyright. All rights reserved.


Lesson: Declaring a Structured Data Object

In this example, a chain statement TYPES: is used to define local structured type
st_connection which consists of the three components airport_from_id, airport_to_id, and
carrier_name. Each component is typed with a data element beginning with /dmo/.
Local structured type st_connection is then used in a DATA statement to type structured
variable connection.

Figure 122: Example: Nested Local Structured Type

In this example, variable connection has a nested structured type. Type st_nested defines 4
components. The first three are typed with data elements, therefore they are simple
components. The fourth component message, however, is typed with a structured type.
Therefore it is a structured component. This makes variable connection nested structure.

Figure 123: Structured Constants

ABAP supports not only structured variables but also structured constants. To define a
structured constant, use BEGIN OF and END OF as part of a CONSTANTS statement. The
example shows a structured constant that is defined in the public section of global class
CL_ABAP_BEHV. All four components are typed with data element SECKEYNAME.
Remember that addition VALUE is mandatory when defining constants.

© Copyright. All rights reserved. 213


Unit 5: Structured Data Objects

Try It Out: Structured Data Types


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

* Example 1 : Motivation for Structured Variables


**********************************************************************

DATA connection_full TYPE /DMO/I_Connection.

SELECT SINGLE
FROM /dmo/I_Connection
FIELDS AirlineID, ConnectionID, DepartureAirport,
DestinationAirport,
DepartureTime, ArrivalTime, Distance, DistanceUnit
WHERE AirlineId = 'LH'
AND ConnectionId = '0400'
INTO @connection_full.

out->write( `--------------------------------------` ).
out->write( `Example 1: CDS View as Structured Type` ).
out->write( connection_full ).

* Example 2: Global Structured Type


**********************************************************************

DATA message TYPE symsg.

out->write( `---------------------------------` ).
out->write( `Example 2: Global Structured Type` ).
out->write( message ).

* Example 3 : Local Structured Type


**********************************************************************

TYPES: BEGIN OF st_connection,


airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.

DATA connection TYPE st_connection.

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport, DestinationAirport, \_Airline-Name
WHERE AirlineID = 'LH'
AND ConnectionID = '0400'
INTO @connection.

out->write( `---------------------------------------` ).
out->write( `Example 3: Global Local Structured Type` ).
out->write( connection ).

* Example 4 : Nested Structured Type


**********************************************************************

TYPES: BEGIN OF st_nested,


airport_from_id TYPE /dmo/airport_from_id,

214 © Copyright. All rights reserved.


Lesson: Declaring a Structured Data Object

airport_to_id TYPE /dmo/airport_to_id,


message TYPE symsg,
carrier_name TYPE /dmo/carrier_name,
END OF st_nested.

DATA connection_nested TYPE st_nested.

out->write( `---------------------------------` ).
out->write( `Example 4: Nested Structured Type` ).
out->write( connection_nested ).

3. Press CTRL + F3 to activate the class and F9 to execute the console app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

LESSON SUMMARY
You should now be able to:
● Declare structured data object

© Copyright. All rights reserved. 215


Unit 5
Lesson 2
Working with Structured Data Objects

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Work with structured data objects
● Use structured data objects in ABAP SQL

Work with Structured Data Objects

Figure 124: Accessing Structure Components

To access a component of a structure, you have to place a minus-sign (-) between the
structure name and the component name.

Note:
No blanks are allowed before or after the component selector.

Accessing a structure component that way, you can use it in any operand position in which
you can use a variable of the same type. Component airport_from_id of structure connection
in the example above is of type /DMO/AIRPORT_FROM_ID. In consequence, you can use this
component in any operand position in which you could use a simple variable of type /DMO/
AIRPORT_FROM_ID; not only on the left-hand side of a value assignment as in the example,
but also on the right-hand side, in the parameter passing of a method call, in the INTO clause
or WHERE clause of a SELECT statement, and so on.

216 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

Figure 125: Accessing the Sub-Components of Nested Structures

If the component of a structure is itself a structure you access the sub-components by using
the component selector again after the name of the main component. The first value
assignment in the example accesses component MSGTY of MESSAGE, which itself is a
component of nested structure CONNECTION_NESTED.

Hint:
You can use code-completion to implement access to structure components.
Place the cursor immediately after the structure component selector and press
CTRL + SPACE to see a list of all available structure components.

Figure 126: Filling a Whole Structure With One Assignment

The VALUE #( ) expression is an elegant way to assign values to a structured data object.
If you want to fill a whole structure, you can address each component individually as you saw
in the previous example.

© Copyright. All rights reserved. 217


Unit 5: Structured Data Objects

However, you can also use a VALUE #( ) expression to fill the structure. The expression
constructs a structure, fills it with value and assigns the filled structure to a variable, in this
case connection. The pound sign (#) tells the ABAP runtime environment to construct a
structure with the same type as the target variable connection. In the brackets, you list the
components of the structure that you want to fill (it does not have to be all of them) and
assign a value to them. The value can be either a literal or the contents of a variable.
When you fill a structure in this way, the runtime system deletes all existing values from the
structure before refilling it with the values from your expression.

Note:
An assignment in the form connection = VALUE #( ). with just a blank between the
brackets, fills all components of the structure with the type-specific initial value.
This has the same effect as statement CLEAR connection.

Figure 127: Value Assignment Between Structures

In ABAP, you may only copy the contents of one structure directly into another structure
using the notation <target structure> = <source structure> if the two structure types are
compatible. This is generally only the case if both structures have the same type. If the
structures have different types, two things can happen:
● If one of the structures has a non-char-like component at a position where the other
structure has a char-like component, direct assignment leads to a syntax error.
● If both structures are char-like, or, in other words, both structures consist of char-like
components, only, direct assignment is technically possible. But usually, the result will be
wrong.

In the example, source structure and target structure are char-like. Therefore, direct
assignment is technically possible. But because they are not compatible the result is wrong:
The content of component carrier_name is copied to component message in the target
structure.

218 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

Note:
Because there is no syntax error, you have to be extra careful when working with
non-compatible char-like structures.

Figure 128: Component-Based Value Assignment

When you copy data between structures, you usually want to copy information from one field
into the corresponding field of the target structure - airport_from_id to airport_from_id,
airport_to_id to airport_to_id, and so on. To achieve this in ABAP, use the CORRESPONDING
expression. This assigns values from <source_structure> to the corresponding, that is,
identically-named components of . <target_structure>. You must remember the following
points:
● The fields must have identical names.
● The components do not have to be in the same position or sequence in the two structures.
● If the fields have different types, ABAP attempts a type conversion according to the
predefined set of rules.

Note:
The target structure is initialized before being re-filled with the result of the
expression.

Try It Out: Access to Structured Data Objects


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

© Copyright. All rights reserved. 219


Unit 5: Structured Data Objects

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

TYPES: BEGIN OF st_connection,


airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.

TYPES: BEGIN OF st_connection_nested,


airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
message TYPE symsg,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection_nested.

DATA connection TYPE st_connection.


DATA connection_nested TYPE st_Connection_nested.

* Example 1: Access to structure components


**********************************************************************

connection-airport_from_id = 'ABC'.
connection-airport_to_id = 'XYZ'.
connection-carrier_name = 'My Airline'.

"Access to sub-components of nested structure


connection_nested-message-msgty = 'E'.
connection_nested-message-msgid = 'ABC'.
connection_nested-message-msgno = '123'.

* Example 2: Filling a structure with VALUE #( ).


**********************************************************************

CLEAR connection.

connection = VALUE #( airport_from_id = 'ABC'


airport_to_id = 'XYZ'
carrier_name = 'My Airline'
).

" Nested VALUE to fill nested structure


connection_nested = VALUE #( airport_from_id = 'ABC'
airport_to_id = 'XYZ'
message = VALUE #( msgty = 'E'
msgid =
'ABC'
msgno =
'123' )
carrier_name = 'My Airline'
).

* Example 3: Wrong result after direct assignment


**********************************************************************

connection_nested = connection.

out-
>write( `-------------------------------------------------------------
` ).
out->write( `Example 3: Wrong Result after direct assignment` ).

out->write( data = connection

220 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

name = `Source Structure:`).

out->write( |Component connection_nested-message-msgid:


{ connection_nested-message-msgid }| ).
out->write( |Component connection_nested-carrier_name :
{ connection_nested-carrier_name }| ).

* Example 4: Assigning Structures using CORRESPONDING #( )


**********************************************************************
CLEAR connection_nested.
connection_nested = CORRESPONDING #( connection ). "

out-
>write( `-------------------------------------------------------------
` ).
out->write( `Example 4: Correct Result after assignment with
CORRESPONDING` ).

out->write( data = connection


name = `Source Structure:`).

out->write( |Component connection_nested-message-msgid:


{ connection_nested-message-msgid }| ).
out->write( |Component connection_nested-carrier_name :
{ connection_nested-carrier_name }| ).

3. Press CTRL + F3 to activate the class and F9 to execute the console app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

Use Structured Data Object in ABAP SQL

Figure 129: Correspondence Between FIELDS and INTO

The INTO clause of the SELECT statement will only work correctly if the number and types of
the components of the structure correspond to the number and types of the columns
specified in the FIELDS clause. In the above example, the statement can only work if the
target structure connection has three components with the same type and length as the
columns DepartureAirport, DestinationAirport, and \_Airline-Name listed in the FIELDS
clause. Note that, in this case, the names do not have to be identical - the system fills the
target structure from left to right.

© Copyright. All rights reserved. 221


Unit 5: Structured Data Objects

Note:
If the field list in the FIELDS clause does not match the structure or table line
type in the INTO clause, a runtime error will occur.

Figure 130: FIELDS * to Read all Fields from a Data Source

The example shows an easy technique to ensure that the target structure matches the field
selection:
● The target structure is typed with CDS view /DMO/I_Connection, which is the data source
in the FROM clause.
● The asterisk sign (*) after keyword FIELDS is a short notation to makes sure, that all fields
of the view are part of the field selection. Exposed associations are ignored.

Note:
This technique is also available when you read directly from a database table. Just
like CDS view definitions, database table definitions can also serve as global
structure types in ABAP.

The main advantage of this technique is, that the SELECT statement stays syntactically intact
even if you or someone else makes changes to CDS view or database table. The most
important drawback is, that you always read all fields from the database, whether you actually
need them or not.

Note:
Only use this technique for views and tables with a small number of fields and if
you actually need all the fields. Unnecessary reading of data from the database is
a major cause for performance problems.

222 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

Figure 131: INTO CORRESPONDING FIELDS OF to Read Only Fields with Corresponding Names

Another way to avoid syntax errors is variant INTO CORRESPONDING FIELDS. This variant
has the same effect as the CORRESPONDING #( ) operator that you learned about earlier. It
ensures that data is copied between identically-named components. By defining the structure
type according to your needs you can ensure that only the required data is read.
Once again, only the names must be identical. But to avoid problems you should make sure
that identically-named components have compatible types. Otherwise the system attempts
to convert the contents of the source field into the type of the target field. This can lead to
data loss or (catchable) runtime errors.

Figure 132: Alias Names for Fields

If the field names in the data source and the component names in the target structure do not
match, the combination of FIELDS * and INTO CORRESPONDING FIELDS OF does not work.
If you want to keep variant INTO CORRESPONDING FIELDS OF, you can define alias names
for the selected fields in the field list. For this, add addition AS after the field name, followed
by the alias name. In the example, the alias name for view field DepartureAirport is
airport_from_id and the alias name for path expression \_Airline-Name is carrier_name.

© Copyright. All rights reserved. 223


Unit 5: Structured Data Objects

Based on this alias names, INTO CORRESPONDING FIELDS OF correctly identifies the
structure component in which to store the retrieved data.

Figure 133: Inline Declarations in INTO clauses

The simplest technique to avoid conflicts between the field selection and the target structure
is an inline declaration in the INTO clause. The sequence, type and name of the inline declared
structure is derived from the FIELD clause. Therefore the target structure always fits the field
selection.

Note:
Inline declarations are only supported after INTO. You cannot use inline
declarations after INTO CORRESPONDING FIELDS OF.

If you use an inline declaration in the INTO clause, you have to provide a name for each
element in the FIELDS clause. For fields of the data source, this can be the field name itself or,
optionally an alias name. For expressions, the alias name becomes mandatory.
In the example, there is no alias for field DepartureAirport. The name of the field is used as
component name in structure connection_inline. Field DestinationAirport has an optional alias
ArrivalAirport. In this case the alias is used as component name. The alias for path expression
\_Airline-Name is mandatory.

224 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

Figure 134: Combining Data From Different Sources (Joins)

When working with a relational database you often face the problem that you have to read
related data from different database tables. We already learned that associations in CDS
views are an elegant way to perform this task.
If no CDS View with suitable associations exist you can implement SQL joins, instead. The
example above illustrates the principle of joins:
We are interested in flight connections and the airports they connect with each other. We find
the 3-letter IDs of the airports in database table /DMO/CONNECTION. The full names of the
airports are stored in database table /DMO/AIRPORT.
To retrieve a connection with the departure airport name, in one SELECT statement, we read
connection data from DB table /DMO/CONNECTION and join it with DB table /DMO/
AIRPORT.
A join consists of the following building blocks:

Data Sources
The Database tables and views to join with each other. A single join always combines a
left-hand data source with a right-hand data source. In the example above, table /DMO/
CONNECTION is the left-hand data source and table /DMO/AIRPORT the right-hand
data source. ABAP SQL also supports joins of joins (nested joins)
Join Condition
The join condition specifies which records of the right-hand data source belong to a
record from the left-hand data source. In the example above, the related departure
airport is identified by the value in columns CLIENT and AIRPORT_ID. The join condition
reads:
/DMO/CONNECTION~CLIENT = /DMO/AIRPORT~CLIENT
AND
/DMO/CONNECTION~AIRPORT_FROM_ID = /DMO/AIRPORT~AIRPORT_ID
Join Type
The join type has an influence on the result if one of the data sources does not contain a
matching records. ABAP SQL currently supports INNER JOIN, LEFT OUTER JOIN, and
RIGHT OUTER JOIN. The most common join type is a LEFT OUTER JOIN.

© Copyright. All rights reserved. 225


Unit 5: Structured Data Objects

Figure 135: Example: Join Syntax in ABAP SQL

The figure shows the ABAP SQL syntax for a join. In the FROM clause, the join type is specified
by keywords LEFT OUTER JOIN between the left-hand data source /dmo/connection and the
right-hand data source /dmo/airport. The syntax introduces alias names c and f for the data
sources. Alias names for data sources are optional, unless a data source appears more than
once in the join.
The join condition follows keyword ON. The separator between the data source or its alias and
the field is the tilde sign (~).

Note:
In ABAP SQL, it is not necessary to mention the client fields. They are added to the
join condition by the database interface before the statement is sent to the
database. If the FROM clause defines a join, you can use fields from both data
sources in the FIELDS and WHERE clauses.

Figure 136: Example: Nested Join

226 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

In this example, the SELECT statement not only read the departure airport name but also the
destination airport name. To do so, the FROM clause defines a nested join:
The first join is a left outer join of tables /dmo/connection and /dmo/airport, introducing
alias "f" (like "from") for the right-hand data source. This first join is then used as left-hand
data source for a second left outer join that has table /dmo/airport as right-hand data source.
Note that in this case alias "t" (for "to") is crucial to distinguish this appearance of
table /dmo/airport from the previous one.
The FIELDS clause, lists the airport names from both data sources, introducing aliases
airport_from_name and airport_to_name to distinguish them from each other.

Hint:
The brackets around the first join are optional. If they are omitted, the joins in the
from clause are evaluated from left to right.

Try It Out: Structured Data Objects in ABAP SQL


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

TYPES: BEGIN OF st_connection,


airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.

TYPES: BEGIN OF st_connection_short,


DepartureAirport TYPE /dmo/airport_from_id,
DestinationAirport TYPE /dmo/airport_to_id,
END OF st_connection_short.

DATA connection TYPE st_connection.

DATA connection_short TYPE st_connection_short.

DATA connection_full TYPE /DMO/I_Connection.

* Example 1: Correspondence between FIELDS and INTO


**********************************************************************

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport, DestinationAirport, \_Airline-Name
WHERE AirlineID = 'LH'
AND ConnectionID = '0400'
INTO @connection.

out->write( `------------------------------` ).
out->write( `Example 1: Field List and INTO` ).
out->write( connection ).

* Example 2: FIELDS *
**********************************************************************

© Copyright. All rights reserved. 227


Unit 5: Structured Data Objects

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS *
WHERE AirlineID = 'LH'
AND ConnectionID = '0400'
INTO @connection_full.

out->write( `----------------------------` ).
out->write( `Example 2: FIELDS * and INTO` ).
out->write( connection_full ).

* Example 3: INTO CORRESPONDING FIELDS


**********************************************************************

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS *
WHERE AirlineID = 'LH'
AND ConnectionID = '0400'
INTO CORRESPONDING FIELDS OF @connection_short.

out->write( `----------------------------------------------------
` ).
out->write( `Example 3: FIELDS * and INTO CORRESPONDING FIELDS
OF` ).
out->write( connection_short ).

* Example 4: Alias Names for Fields


**********************************************************************

CLEAR connection.

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport AS airport_from_id,
\_Airline-Name AS carrier_name
WHERE AirlineID = 'LH'
AND ConnectionID = '0400'
INTO CORRESPONDING FIELDS OF @connection.

out->write( `---------------------------------------------------
` ).
out->write( `Example 4: Aliases and INTO CORRESPONDING FIELDS
OF` ).
out->write( connection ).

* Example 5: Inline Declaration


**********************************************************************

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport,
DestinationAirport AS ArrivalAirport,
\_Airline-Name AS carrier_name
WHERE AirlineID = 'LH'
AND ConnectionID = '0400'
INTO @DATA(connection_inline).

out->write( `-----------------------------------------` ).
out->write( `Example 5: Aliases and Inline Declaration` ).
out->write( connection_inline ).

* Example 6: Joins

228 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

**********************************************************************

SELECT SINGLE
FROM ( /dmo/connection AS c
LEFT OUTER JOIN /dmo/airport AS f
ON c~airport_from_id = f~airport_id )
LEFT OUTER JOIN /dmo/airport AS t
ON c~airport_to_id = t~airport_id
FIELDS c~airport_from_id, c~airport_to_id,
f~name AS airport_from_name, t~name AS airport_to_name
WHERE c~carrier_id = 'LH'
AND c~connection_id = '0400'
INTO @DATA(connection_join).

out->write( `------------------------------------------` ).
out->write( `Example 6: Join of Connection and Airports` ).
out->write( connection_join ).

3. Press CTRL + F3 to activate the class and F9 to execute the console app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

© Copyright. All rights reserved. 229


Unit 5: Structured Data Objects

230 © Copyright. All rights reserved.


Unit 5
Exercise 9
Use a Structured Data Object

Task 1: Preparation

1. If you finished the previous exercise Analyze and Use a CDS View Entity, create a copy of
your global class ZCL_##_CDS, and name the copy ZCL_##_STRUCTURE, where ## is your
group number. Then skip the rest of this task.

2. If you did not finish the previous exercise, create a new global class ZCL_##_STRUCTURE,
where ## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'LH'
i_connection_id = '0400'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Second instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'AA'
i_connection_id = '0017'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Third instance
**********************************************************************

TRY.

© Copyright. All rights reserved. 231


Unit 5: Structured Data Objects

connection = NEW #(
i_carrier_id = 'SQ'
i_connection_id = '0001'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Output
**********************************************************************

LOOP AT connections INTO connection.

out->write( connection->get_output( ) ).

ENDLOOP.

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

CLASS-DATA conn_counter TYPE i.

METHODS constructor
IMPORTING
i_connection_id TYPE /dmo/connection_id
i_carrier_id TYPE /dmo/carrier_id
RAISING
cx_ABAP_INVALID_VALUE .

METHODS get_output
RETURNING
VALUE(r_output) TYPE string_table.

PROTECTED SECTION.

PRIVATE SECTION.
DATA carrier_id TYPE /dmo/carrier_id.
DATA connection_id TYPE /dmo/connection_id.

DATA airport_from_id TYPE /dmo/airport_from_id.


DATA airport_to_id TYPE /dmo/airport_to_id.

DATA carrier_name TYPE /dmo/carrier_name.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD constructor.

" ensure non-initial input


IF carrier_id IS INITIAL OR connection_id IS INITIAL.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

" check existence and read additional data


SELECT SINGLE

232 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

FROM /DMO/I_Connection
FIELDS DepartureAirport, DestinationAirport, \_Airline-Name
WHERE AirlineID = @i_carrier_id
AND ConnectionID = @i_connection_id
INTO ( @airport_from_id, @airport_to_id, @carrier_name ).

IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

me->connection_id = i_connection_id.
me->carrier_id = i_carrier_id.

conn_counter = conn_counter + 1.

ENDMETHOD.

METHOD get_output.

APPEND |--------------------------------| TO r_output.


APPEND |Carrier: { carrier_id } { carrier_name }| TO r_output.
APPEND |Connection: { connection_id }| TO r_output.
APPEND |Departure: { airport_from_id }| TO r_output.
APPEND |Destination: { airport_to_id }| TO r_output.

ENDMETHOD.

ENDCLASS.

Task 2: Declare a Structured Variable


Define a structured attribute details to replace scalar attributes airport_from_id,
airport_to_id, and carrier_name.

1. Switch to the local class lcl_connection.

2. Add a private structure type st_details with the folowing components:

Table 3: Components of structure type st_details


Component Name Data Type
DepartureAirport /DMO/AIRPORT_FROM_ID

DestinationAirport /DMO/AIRPORT_TO_ID

AirlineName /DMO/CARRIER_NAME

3. Declare a new private instance attribute details and type it with structure type
st_details..

4. Comment or remove the declaration of attributes airport_from_id, airport_to_id,


and carrier_name.

Task 3: Access Structure Components


Use the components of structured attribute details in method get_output( ).

1. Adjust the implementation of method get_output( ). Replace any access to attributes


airport_from_id, airport_to_id, and carrier_name with the corresponding
component of attribute details.

© Copyright. All rights reserved. 233


Unit 5: Structured Data Objects

Hint:
Do not type in the component names manually. After typing the structure
component selector (-), press Ctrl + Space to get a list of all components.

Task 4: Fill Structured Attribute in SELECT Statement


Use the structured attribute as target of the SELECT statement in method constructor( ).

1. Adjust the SELECT statement in the implementation of method constructur( ).


Replace the list of data objects in the INTO clause with the structured attribute details.

2. Optional: Use syntax variant INTO CORRESPONDING FIELDS OF @details..

3. Activate the class. Execute it and analyze the console output. Check that the output
displays data for all attributes.

234 © Copyright. All rights reserved.


Unit 5
Solution 9
Use a Structured Data Object

Task 1: Preparation

1. If you finished the previous exercise Analyze and Use a CDS View Entity, create a copy of
your global class ZCL_##_CDS, and name the copy ZCL_##_STRUCTURE, where ## is your
group number. Then skip the rest of this task.
a) In the Project Explorer view on the left, expand your package.

b) Expand node Source Code Library → Classes

c) Right-click the name of the class you want to copy and choose Duplicate.

d) In the Name field, enter the name ZCL_##_STRUCTURE, where ## is your group
number.

e) Choose Next.

f) Select your transport request and choose Finish.

2. If you did not finish the previous exercise, create a new global class ZCL_##_STRUCTURE,
where ## is your group number. Ensure that the class implements the interface
IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_STRUCTURE, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

3. Copy the following code between METHOD if_oo_adt_classrun~main. and


ENDMETHOD. on the Global Class tab:

DATA connection TYPE REF TO lcl_connection.


DATA connections TYPE TABLE OF REF TO lcl_connection.

* First Instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'LH'
i_connection_id = '0400'

© Copyright. All rights reserved. 235


Unit 5: Structured Data Objects

).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Second instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'AA'
i_connection_id = '0017'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Third instance
**********************************************************************

TRY.
connection = NEW #(
i_carrier_id = 'SQ'
i_connection_id = '0001'
).

APPEND connection TO connections.

CATCH cx_abap_invalid_value.
out->write( `Method call failed` ).
ENDTRY.

* Output
**********************************************************************

LOOP AT connections INTO connection.

out->write( connection->get_output( ) ).

ENDLOOP.

a) Navigate to the Global Class tab and insert the source code between METHOD
if_oo_adt_classrun~main. and ENDMETHOD..

4. Copy the following code to the Local Types tab:

CLASS lcl_connection DEFINITION.

PUBLIC SECTION.

CLASS-DATA conn_counter TYPE i.

METHODS constructor
IMPORTING
i_connection_id TYPE /dmo/connection_id
i_carrier_id TYPE /dmo/carrier_id
RAISING

236 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

cx_ABAP_INVALID_VALUE .

METHODS get_output
RETURNING
VALUE(r_output) TYPE string_table.

PROTECTED SECTION.

PRIVATE SECTION.
DATA carrier_id TYPE /dmo/carrier_id.
DATA connection_id TYPE /dmo/connection_id.

DATA airport_from_id TYPE /dmo/airport_from_id.


DATA airport_to_id TYPE /dmo/airport_to_id.

DATA carrier_name TYPE /dmo/carrier_name.

ENDCLASS.

CLASS lcl_connection IMPLEMENTATION.

METHOD constructor.

" ensure non-initial input


IF carrier_id IS INITIAL OR connection_id IS INITIAL.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

" check existence and read additional data


SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport, DestinationAirport, \_Airline-Name
WHERE AirlineID = @i_carrier_id
AND ConnectionID = @i_connection_id
INTO ( @airport_from_id, @airport_to_id, @carrier_name ).

IF sy-subrc <> 0.
RAISE EXCEPTION TYPE cx_abap_invalid_value.
ENDIF.

me->connection_id = i_connection_id.
me->carrier_id = i_carrier_id.

conn_counter = conn_counter + 1.

ENDMETHOD.

METHOD get_output.

APPEND |--------------------------------| TO r_output.


APPEND |Carrier: { carrier_id } { carrier_name }| TO r_output.
APPEND |Connection: { connection_id }| TO r_output.
APPEND |Departure: { airport_from_id }| TO r_output.
APPEND |Destination: { airport_to_id }| TO r_output.

ENDMETHOD.

ENDCLASS.

a) Navigate to the Local Types tab and insert the source code.

Task 2: Declare a Structured Variable


Define a structured attribute details to replace scalar attributes airport_from_id,
airport_to_id, and carrier_name.

© Copyright. All rights reserved. 237


Unit 5: Structured Data Objects

1. Switch to the local class lcl_connection.


a) In the global class, choose Local Types.

2. Add a private structure type st_details with the folowing components:

Table 3: Components of structure type st_details


Component Name Data Type
DepartureAirport /DMO/AIRPORT_FROM_ID

DestinationAirport /DMO/AIRPORT_TO_ID

AirlineName /DMO/CARRIER_NAME

a) After line PRIVATE SECTION. , add the following code:

TYPES: BEGIN OF st_details,


DepartureAirport TYPE /dmo/airport_from_id,
DestinationAirport TYPE /dmo/airport_to_id,
AirlineName TYPE /dmo/carrier_name,
END OF st_details.

3. Declare a new private instance attribute details and type it with structure type
st_details..
a) Insert the following code after DATA carrier_name TYPE /dmo/
carrier_name..

DATA details TYPE st_details.

4. Comment or remove the declaration of attributes airport_from_id, airport_to_id,


and carrier_name.

Task 3: Access Structure Components


Use the components of structured attribute details in method get_output( ).

1. Adjust the implementation of method get_output( ). Replace any access to attributes


airport_from_id, airport_to_id, and carrier_name with the corresponding
component of attribute details.

Hint:
Do not type in the component names manually. After typing the structure
component selector (-), press Ctrl + Space to get a list of all components.

a) Navigate to the implementation of method get_output( ).

b) Adjust the APPEND statements as follows:

* APPEND |--------------------------------| TO r_output.


* APPEND |Carrier: { carrier_id } { carrier_name }| TO r_output.
* APPEND |Connection: { connection_id }| TO r_output.
* APPEND |Departure: { airport_from_id }| TO r_output.
* APPEND |Destination: { airport_to_id }| TO r_output.

238 © Copyright. All rights reserved.


Lesson: Working with Structured Data Objects

APPEND |--------------------------------| TO
r_output.
APPEND |Carrier: { carrier_id } { details-airlinename }| TO
r_output.
APPEND |Connection: { connection_id }| TO
r_output.
APPEND |Departure: { details-departureairport }| TO
r_output.
APPEND |Destination: { details-destinationairport }| TO
r_output.

Task 4: Fill Structured Attribute in SELECT Statement


Use the structured attribute as target of the SELECT statement in method constructor( ).

1. Adjust the SELECT statement in the implementation of method constructur( ).


Replace the list of data objects in the INTO clause with the structured attribute details.
a) Navigate to the implementation of method constructor( ).

b) Adjust the SELECT statement as follows:

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport, DestinationAirport, \_Airline-Name
WHERE AirlineID = @i_carrier_id
AND ConnectionID = @i_connection_id
* INTO ( @airport_from_id, @airport_to_id, @carrier_name ).
INTO @details.

2. Optional: Use syntax variant INTO CORRESPONDING FIELDS OF @details..


a) In the SELECT statement, replace INTO @details.with the following code:

INTO CORRESPONDING FIELDS OF @details.

b) Add alias name AirlineName for the path expression.

c) The SELECT statement should now look like this:

SELECT SINGLE
FROM /DMO/I_Connection
FIELDS DepartureAirport, DestinationAirport, \_Airline-Name as
AirlineName
WHERE AirlineID = @i_carrier_id
AND ConnectionID = @i_connection_id
INTO CORRESPONDING FIELDS OF @details.

3. Activate the class. Execute it and analyze the console output. Check that the output
displays data for all attributes.
a) Press Ctrl + F3 to activate the class.

b) Press F9 to run the class.

© Copyright. All rights reserved. 239


Unit 5: Structured Data Objects

LESSON SUMMARY
You should now be able to:
● Work with structured data objects
● Use structured data objects in ABAP SQL

240 © Copyright. All rights reserved.


Unit 5

Learning Assessment

1. You declare a variable using the statement DATA struct TYPE <type>. Which of the
following can you use to declare a structure?
Choose the correct answers.

X A A database table

X B A data element

X C A CDS view

X D A predefined ABAP type

2. A structure struct contains a component comp. How do you address the component?
Choose the correct answer.

X A struct.comp

X B struct-comp

X C struct->comp

X D struct=>comp

© Copyright. All rights reserved. 241


Unit 5: Learning Assessment

242 © Copyright. All rights reserved.


UNIT 6 Complex Internal Tables

Lesson 1
Declaring a Complex Internal Table 245

Lesson 2
Working with Complex Internal Tables 253

UNIT OBJECTIVES

● Declare a complex internal table


● Fill complex internal tables with data
● Access the content of complex internal tables
● Use complex internal tables in ABAP SQL

© Copyright. All rights reserved. 243


Unit 6: Complex Internal Tables

244 © Copyright. All rights reserved.


Unit 6
Lesson 1
Declaring a Complex Internal Table

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Declare a complex internal table

Properties of Complex Internal Tables

Figure 137: Reminder - Simple Internal Tables

The internal tables we have used so far had a scalar data type as their row type. In the
example shown in the figures here, the row type of internal table numbers is the ABAP built-in
type I.
We refer to these kinds of internal tables as simple internal tables.

© Copyright. All rights reserved. 245


Unit 6: Complex Internal Tables

Figure 138: Internal Tables with Structured Row Type

We speak of a complex internal table if the row type is a structured data type.
While a simple internal table has only one nameless column, a complex internal table consists
of several columns, each of them with the name and type of the corresponding component of
the structured row type. In the example, the row type of internal table connection is a
structured type with five components: carrier_id, connection_id, airport_from_id,
airport_to_id, and carrier_name. Consequently, internal table connections has five columns
with those names.

Note:
The columns in the examples in the figures, Reminder: Simple Internal Tables and
Internal Tables with Structured Row Type, all have scalar types. More generally, a
column of an internal table could also be of structured type or even have a table
type. In the latter case, we talk of a nested internal table.

Figure 139: Addressing Internal Tables - Index Access and Key Access

Up to now, we have addressed the rows of an internal table by their position. This is called an
index access.

246 © Copyright. All rights reserved.


Lesson: Declaring a Complex Internal Table

With the named columns of a complex internal table, key access becomes more important.
Key access means addressing a row of the internal table by looking for particular values in
particular columns. The columns in which you search can be any columns of the internal
table.
Index access to an internal table is always very fast, even if the internal table contains many
rows. Key access, however, can become very slow if the table contains a lot of rows. Choosing
the right access type for the internal table can improve the performance of a key access.

Figure 140: Access Type of Internal Tables

Every internal table has one of three access types. The access type determines how data is
stored in the table and, based on that, how the system reads the table to retrieve the data.
The different types of tables are as follows:

Animation
For more information on this topic please view the animation in the lesson
Declaring a Complex Internal Table in your online course.

Standard Table
In a standard table, the contents are not stored in a particular sort order. By default, new
records are appended to the end of the table. In order to retrieve data by key, the system
must read it sequentially, which can lead to long retrieval times if the table is very large.
The simple internal tables we used so far were standard tables.
Sorted Table
In a sorted table, the contents of the table are always sorted according to the key fields in
ascending order. When you insert a new record into the table, the system ensures that it
is placed at the correct position. Since the data is always sorted, the system can retrieve
records more efficiently than from a standard table (as long as you follow particular
rules).
Hashed Table
Hashed tables are managed using a special hash algorithm. This ensures that the system
can retrieve records very quickly even if the table is extremely large. However, this
performance gain only works in very particular cases.

© Copyright. All rights reserved. 247


Unit 6: Complex Internal Tables

Note:
In this lesson, we will concentrate on standard tables. More information on sorted
and hashed tables can be found in the ABAP documentation.

Figure 141: Key Definition of an Internal Table

Every internal table has a key. In standard tables, the key does not play a particularly
significant role. For sorted and hashed tables, the key is very important as it determines the
way in which the data will be managed in the table. Crucially, sorted and hashed tables are
only faster for key access that addresses all or at least a subset of the key fields.
A further attribute of the table key is its uniqueness. You will sometimes want to allow
duplicate entries in an internal table, and sometimes you will want to ensure that the key is
unique. Here, the following rules apply:
● Duplicates are always allowed in standard tables
● Duplicates are never allowed in hashed tables
● For a sorted table, you choose in the definition whether the key is to be unique or non-
unique.

Note:
Internal tables may also have secondary keys. Secondary keys are a way of
improving the performance of key accesses to internal tables that use different
combinations of fields. You will find more information about secondary keys in the
ABAP syntax documentation.

248 © Copyright. All rights reserved.


Lesson: Declaring a Complex Internal Table

Complex Table Types

Figure 142: Examples - Complex Internal Tables

Here you will see some examples for the declaration of complex internal tables.

Animation
For more information on this topic please view the animation in the lesson
Declaring a Complex Internal Table in your online course.

The figure, Examples - Complex Internal Tables, shows some examples for the declaration of
complex internal tables.
The first example specifies neither the access type nor the key attributes. The ABAP compiler
implicitly declares a standard table with a non-unique standard key. The standard key, or
default key, consists of all non-numeric columns of the table line type.
For simple internal tables, where the access type and key definition is not important, the short
syntax is acceptable. For complex internal tables, you should clearly specify the access type
and key. The second example defines an internal table of exactly the same type as the first
example, but instead of using the short form it explicitly specifies the access type and the key.
The third and forth internal tables define internal tables of access type sorted and hashed. For
these access types the definition of the key is mandatory.

© Copyright. All rights reserved. 249


Unit 6: Complex Internal Tables

Figure 143: Defining Table Types Locally

Furthermore, it is good programming style to define the data type first and then to create a
variable that refers to the type.
Instead of specifying the access type and key of an internal table in the DATA statement, you
should use a named table type. If you need the table type only locally in a method or in
connection with a given class, you can define it using the TYPES statement.
The example defines a structured type st_connection, first. With this structured type as row
type it then defines table type tt_connections. Finally, the declaration of internal table
connections_5 refers to the table type.

Figure 144: Global Table Types

If you need the table type globally, you can use a global table type.
A global table type is a repository object that can be used as data type anywhere in the
system. ADT provides a dedicated editor for this kind of repository object. The tool consists of
the following frames:

250 © Copyright. All rights reserved.


Lesson: Declaring a Complex Internal Table

Animation
For more information on this topic please view the animation in the lesson
Declaring a Complex Internal Table in your online course.

Row Type
This frame contains the origin and name of the row type. In the example, global
type /DMO/FLIGHT is used.
Initialization and Access
Among other things, this frame contains the definition of the access type. In the example,
the access type - Standard Table - is selected.
Key Overview
This frame provides an overview of the keys. Choose the key for which you want to see
details on the right.

Note:
Every table type contains the definition of a primary key. Secondary keys are
optional. The table type in the example does not contain any secondary
keys.

Key Details
This frame displays details for the selected key: the key category, that is, whether the key
is unique or non-unique, and the list of key components. In the example, the primary key
is non-unique and consists of components CLIENT, CARRIER_ID, CONNECTION_ID, and
FLIGHT_DATE.

Try It Out: Complex Table Types


1. Like in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method,


if_oo_adt_classrun~main( ):

TYPES: BEGIN OF st_connection,


carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.

* Example 1 : Simple and Complex Internal Table


**********************************************************************

" simple table (scalar row type)


DATA numbers TYPE TABLE OF i.
" complex table (structured row type)
DATA connections TYPE TABLE OF st_connection.

out->write( `--------------------------------------------` ).
out->write( `Example 1: Simple and Complex Internal Table` ).

© Copyright. All rights reserved. 251


Unit 6: Complex Internal Tables

out->write( data = numbers


name = `Simple Table NUMBERS:`).
out->write( data = connections
name = `Complex Table CONNECTIONS:`).

* Example 2 : Complex Internal Tables


**********************************************************************

" standard table with non-unique standard key (short form)


DATA connections_1 TYPE TABLE OF st_connection.

" standard table with non-unique standard key (explicit form)


DATA connections_2 TYPE STANDARD TABLE OF st_connection
WITH NON-UNIQUE DEFAULT KEY.

" sorted table with non-unique explicit key


DATA connections_3 TYPE SORTED TABLE OF st_connection
WITH NON-UNIQUE KEY airport_from_id
airport_to_id.

" sorted hashed with unique explicit key


DATA connections_4 TYPE HASHED TABLE OF st_connection
WITH UNIQUE KEY carrier_id
connection_id.

* Example 3 : Local Table Type


**********************************************************************

TYPES tt_connections TYPE SORTED TABLE OF st_connection


WITH UNIQUE KEY carrier_id
connection_id.

DATA connections_5 TYPE tt_connections.

* Example 4 : Global Table Type


**********************************************************************

DATA flights TYPE /dmo/t_flight.

out->write( `------------------------------------------` ).
out->write( `Example 4: Global Table TYpe /DMO/T_FLIGHT` ).
out->write( data = flights
name = `Internal Table FLIGHTS:` ).

3. Press CTRL + F3 on your keyboard to activate the class and F9 to execute the console
app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

LESSON SUMMARY
You should now be able to:
● Declare a complex internal table

252 © Copyright. All rights reserved.


Unit 6
Lesson 2
Working with Complex Internal Tables

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Fill complex internal tables with data
● Access the content of complex internal tables
● Use complex internal tables in ABAP SQL

Filling Complex Internal Tables

Figure 145: APPEND for Complex Internal Tables - Declaration of a Work Area

As you already learned, the simplest way to add a new row to an internal table is the APPEND
statement with a data object whose type corresponds to the row type of the internal table.
This data object is sometimes referred to as work area.
For simple internal tables the work area used in APPEND can be a scalar variable, constant, or
a literal. For complex internal tables, the work area has to be structured.
In the example, structured variable connection is used to fill internal table connections.
In principle, there are two ways to declare work area connection:
● Reference the row type st_connection directly
● Reference the row type indirectly using LIKE LINE OF <internal_table>.

Defining work areas with LIKE LINE OF has two advantages:

© Copyright. All rights reserved. 253


Unit 6: Complex Internal Tables

● It reveals the purpose of the structured variable as work area for the internal table
● It ensures that the work area fits to the internal table, even if the definition of the internal
table changes

Figure 146: APPEND for Complex Internal Tables - Filling the Work Area

If you do not fill the work area before the APPEND statement, the new row of the internal table
will be filled with type-specific initial values.

Hint:
You get the same result with the special variant APPEND INITIAL LINE TO
<internal_table>. This variant does not even require a work area.

To fill the structured work area, you can either fill the individual components or, as you can
see in the example, use a VALUE #( ) expression.

Figure 147: APPEND for Complex Internal Tables - direct use of VALUE #( )

254 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

As you can see in the example, you can also use a VALUE #( ) expression directly in the
APPEND statement. In this case, you do not need a work area.

Note:
This can have a positive effect on the overall memory consumption of your
program.

Figure 148: Filling an Internal Table with Several Rows

There is a variant of the VALUE #( ) expression that you can assign directly to an internal
table. In this variant of VALUE #( ) additional pairs of brackets are used to separate the table
rows from each other.
The code example fills internal table carriers with three rows, each with a different value for
carrier_id and carrier_name. As a result of this, column currency_code is not mentioned, it is
filled with the type specific initial value.

Note:
With the assignment above, all existing table rows are removed before the table is
filled with the new rows.

© Copyright. All rights reserved. 255


Unit 6: Complex Internal Tables

Figure 149: Filling one Internal Table from Another

To copy data between identically-named fields of two internal tables, use the
CORRESPONDING operator. This works similarly to CORRESPONDING for structures: for
each row of the source internal table, the system creates a new row in the target internal table
and copies data between identically-named fields. Source fields for which there is no
identically named field in the target are not copied. Target fields for which there is no
identically named field in the source are filled with type-specific initial values.
In the example, the source internal table carriers contains three rows. Therefore, after the
value assignment, the target internal table connections also contains three rows.
Fields carrier_id and carrier_name exist in both internal tables. They are copied from source
to target. Field currency_code only exists in the source. It is not copied. Fields connection_id,
airport_from_id, and airport_to_id exist only in the target. They are filled with initial values.

Note:
If the target internal table contains data before the assignment, the system
deletes it.

Try It Out: Filling Complex Internal Tables


1. As it is in the first exercise of this course, create a new global class that implements
interface IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

TYPES: BEGIN OF st_connection,


carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.

256 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

TYPES tt_connections TYPE STANDARD TABLE OF st_connection


WITH NON-UNIQUE KEY carrier_id
connection_id.

DATA connections TYPE tt_connections.

TYPES: BEGIN OF st_carrier,


carrier_id TYPE /dmo/carrier_id,
carrier_name TYPE /dmo/carrier_name,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.

TYPES tt_carriers TYPE STANDARD TABLE OF st_carrier


WITH NON-UNIQUE KEY carrier_id.

DATA carriers TYPE tt_carriers.

* Example 1: APPEND with structured data object (work area)


**********************************************************************

* DATA connection TYPE st_connection.


" Declare the work area with LIKE LINE OF
DATA connection LIKE LINE OF connections.

* connection-carrier_id = 'NN'.
* connection-connection_id = '1234'.
* connection-airport_from_id = 'ABC'.
* connection-airport_to_id = 'XYZ'.
* connection-carrier_name = 'My Airline'.

" Use VALUE #( ) instead assignment to individual components


connection = VALUE #( carrier_id = 'NN'
connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline' ).

APPEND connection TO connections.

out->write( `--------------------------------` ).
out->write( `Example 1: APPEND with Work Area` ).
out->write( connections ).

* Example 2: APPEND with VALUE #( ) expression


**********************************************************************

APPEND VALUE #( carrier_id = 'NN'


connection_id = '1234'
airport_from_id = 'ABC'
airport_to_id = 'XYZ'
carrier_name = 'My Airline'
)
TO connections.

out->write( `----------------------------` ).
out->write( `Example 2: Append with VALUE` ).
out->write( connections ).

* Example 3: Filling an Internal Table with Several Rows


**********************************************************************

carriers = VALUE #( ( carrier_id = 'AA' carrier_name = 'American


Airlines' )

© Copyright. All rights reserved. 257


Unit 6: Complex Internal Tables

( carrier_id = 'JL' carrier_name = 'Japan


Airlines' )
( carrier_id = 'SQ' carrier_name =
'Singapore Airlines')
).

out->write( `-----------------------------------------` ).
out->write( `Example 3: Fill Internal Table with VALUE` ).
out->write( carriers ).

* Example 4: Filling one Internal Table from Another


**********************************************************************

connections = CORRESPONDING #( carriers ).

out->write( `--------------------------------------------` ).
out->write( `Example 4: CORRESPONDING for Internal Tables` ).
out->write( data = carriers
name = `Source Table CARRIERS:`).
out->write( data = connections
name = `Target Table CONNECTIONS:`).

3. Press CTRL + F3 on your keyboard to activate the class and F9 to execute the console
app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

Accessing the Content of Complex Internal Tables

Figure 150: Internal Table Expressions with Key Access

Earlier in this course, you learned how to retrieve a single row from a simple internal table
using an internal table expression. Back then we used an index access, that is, we identified
the row through its position in the internal table. This index access works for complex internal
tables in just the same way. For complex internal tables, however, internal table expressions
with key access become important, where you identify the row through its content.

258 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

Note:
Even though this is called a key access, you can use any fields for the selection,
not only key fields of the internal table. If more than one row fulfills the
requirement, the first row is returned, that is, the row with the lowest index.

The example reads a single row from internal table connections. The key of this internal table
consists of fields, carrier_id and connection_id, but the key access uses airport_from_id and
airport_to_id to identify the row. The Internal table contains two connections from airport SFO
to SIN, so the first of them is returned.

Note:
Remember that the ABAP runtime raises exception
CX_SY_ITAB_LINE_NOT_FOUND if none of the rows fulfills the requirement.
Handle this exception in a TRY … CATCH … ENDTRY structure to avoid runtime
errors

Figure 151: LOOP … ENDLOOP with Key Access

To process multiple lines of an internal table by specifying fields, you use LOOP AT <internal
table> INTO <target> WHERE <condition>. The WHERE condition can contain any number of
constituent expressions joined using AND and OR. Within the expressions, you can use not
just the equals operator (=) but also operators >, >=, <, <=, <> and BETWEEN.

© Copyright. All rights reserved. 259


Unit 6: Complex Internal Tables

Figure 152: Updating a Table Row with Key Access

After reading the content of a table row into a work area, you sometimes want to write
changes from the work area back into the internal table. One way to do this is the MODIFY
TABLE statement.
This statement is a key access because the system uses the content of the key fields in the
work area to identify the table row that needs to be modified. It then overwrites this table row
with the contents of the work area.
In the example, the work area carrier contains value 'JL' in key field, carrier_id. Based on this
value, the system identifies the second row to be updated. This row is then updated with the
values from the work area.

Note:
You can only change non-key fields with MODIFY TABLE. The statement does not
support changes to key fields.

Figure 153: Updating a Table Row with Index Access

260 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

The MODIFY statement (without keyword TABLE!) does not distinguish between key fields
and non-key fields. It overwrites the entire table row with new values from the work area. This
statement is considered an index access because the row to be updated is identified by its
position in the internal table. Usually, the index is specified explicitly using addition INDEX
followed by an integer argument (literal, constant, variable, expression).

Note:
There is also a special variant without addition INDEX. We will discuss this variant
next.

In the example, the MODIFY statement uses the INDEX addition to address the first table row.
In this row, all fields are overwritten with the values from the work area, even key field
carrier_id.

Figure 154: Updating Multiple Table Rows in a LOOP

There will often be times when you need to modify the contents of multiple rows of an internal
table, or maybe even all of them. To do this, you implement a loop over the table, which places
each row you need to change successively into a work area. Within the loop, you first change
the contents of the work area and then write the changes back into the internal table using the
MODIFY statement.

Note:
If you do not write your changes back into the table, the changes will be lost when
the work area is filled with the data from next row.

In the example, the loop reads all rows of internal table carriers for which field currency_code
is not yet filled. This is the case for the last two rows. For each of these rows the program
replaces the initial value in field currency_code with the new value 'USD'. Finally, it uses the
MODIFY statement to overwrite the current row with the updated values.
Instead of specifying the index explicitly, the code example uses a short form of the MODIFY
statement where the INDEX addition is missing. This short form is only allowed between

© Copyright. All rights reserved. 261


Unit 6: Complex Internal Tables

LOOP … ENDLOOP. Only there the system can implicitly update the row it is currently working
on.

Note:
If you use MODIFY without INDEX outside of LOOP…ENDLOOP, the system does
not know which row to modify and triggers a non-catchable runtime error. To
avoid such runtime errors, make sure not to ignore the related warning from the
syntax check!

Try It Out: Accessing Complex Internal Tables


1. As with the first exercise of this course, create a new global class that implements the
interface, IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

TYPES: BEGIN OF st_connection,


carrier_id TYPE /dmo/carrier_id,
connection_id TYPE /dmo/connection_id,
airport_from_id TYPE /dmo/airport_from_id,
airport_to_id TYPE /dmo/airport_to_id,
carrier_name TYPE /dmo/carrier_name,
END OF st_connection.

TYPES tt_connections TYPE SORTED TABLE OF st_connection


WITH NON-UNIQUE KEY carrier_id
connection_id.

DATA connections TYPE tt_connections.


DATA connection LIKE LINE OF connections.

TYPES: BEGIN OF st_carrier,


carrier_id TYPE /dmo/carrier_id,
currency_code TYPE /dmo/currency_code,
END OF st_carrier.

DATA carriers TYPE STANDARD TABLE OF st_carrier


WITH NON-UNIQUE KEY carrier_id.

DATA carrier LIKE LINE OF carriers.

* Preparation: Fill internal tables with data


**********************************************************************
connections = VALUE #( ( carrier_id = 'JL'
connection_id = '0408'
airport_from_id = 'FRA'
airport_to_id = 'NRT'
carrier_name = 'Japan Airlines'
)
( carrier_id = 'AA'
connection_id = '0017'
airport_from_id = 'MIA'
airport_to_id = 'HAV'
carrier_name = 'American Airlines'
)
( carrier_id = 'SQ'
connection_id = '0001'
airport_from_id = 'SFO'

262 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

airport_to_id = 'SIN'
carrier_name = 'Singapore Airlines'
)
( carrier_id = 'UA'
connection_id = '0078'
airport_from_id = 'SFO'
airport_to_id = 'SIN'
carrier_name = 'United Airlines'
)
).

carriers = VALUE #( ( carrier_id = 'SQ'


currency_code = ' '
)
( carrier_id = 'JL'
currency_code = ' '
)
( carrier_id = 'AA'
currency_code = ' '
)
( carrier_id = 'UA'
currency_code = ' '
)
).

* Example 1: Table Expression with Key Access


**********************************************************************
out->write( `--------------------------------------------` ).
out->write( `Example 1: Table Expressions with Key Access` ).

out->write( data = connections


name = `Internal Table CONNECTIONS: ` ).

" with key fields


connection = connections[ carrier_id = 'SQ'
connection_id = '0001' ].

out->write( data = connection


name = `CARRIER_ID = 'SQ' AND CONNECTION_ID =
'001':` ).

" with non-key fields


connection = connections[ airport_from_id = 'SFO'
airport_to_id = 'SIN' ].
out->write( data = connection
name = `AIRPORT_FROM_ID = 'SFO' AND AIRPORT_TO_ID =
'SIN':` ).

* Example 2: LOOP with key access


**********************************************************************

out->write( `-------------------------------` ).
out->write( `Example 2: LOOP with Key Access` ).

LOOP AT connections INTO connection


WHERE airport_from_id <> 'MIA'.

"do something with the content of connection


out->write( data = connection
name = |This is row number { sy-tabix }: | ).

ENDLOOP.

* Example 3: MODIFY TABLE (key access)

© Copyright. All rights reserved. 263


Unit 6: Complex Internal Tables

**********************************************************************
out->write( `-----------------------------------` ).
out->write( `Example 3: MODIFY TABLE (key access` ).

out->write( data = carriers


name = `Table CARRRIERS before MODIFY TABLE:`).

carrier = carriers[ carrier_id = 'JL' ].


carrier-currency_code = 'JPY'.
MODIFY TABLE carriers FROM carrier.

out->write( data = carriers


name = `Table CARRRIERS after MODIFY TABLE:`).

* Example 4: MODIFY (index access)


**********************************************************************
out->write( `--------------------------------` ).
out->write( `Example 4: MODIFY (index access)` ).

carrier-carrier_id = 'LH'.
carrier-currency_code = 'EUR'.
MODIFY carriers FROM carrier INDEX 1.

out->write( data = carriers


name = `Table CARRRIERS after MODIFY:`).

* Example 5: MODIFY in a LOOP


**********************************************************************
out->write( `----------------------------` ).
out->write( `Example 5: MODIFY in a LOOP` ).

LOOP AT carriers INTO carrier


WHERE currency_code IS INITIAL.

carrier-currency_code = 'USD'.
MODIFY carriers FROM carrier.

ENDLOOP.

out->write( data = carriers


name = `Table CARRRIERS after the LOOP:`).

3. Press CTRL + F3 on your keyboard to activate the class and F9 to execute the console
app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

264 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

Complex Internal Tables in ABAP SQL

Figure 155: Reminder: Structured Variables in SELECT SINGLE … INTO …

The ABAP SQL statement, SELECT, reads data from a database table or a CDS View. When
you use the SINGLE option, exactly one record is read from the database, even if more data
exist that meets the conditions in the WHERE clause.
As you learned earlier, one way to receive this single record result is structured variable after
keyword INTO.

Figure 156: Internal Table in SELECT … INTO TABLE …

If you use SELECT without SINGLE, you indicate that you are interested in all records that
match the conditions in the WHERE clause. You then have to make sure that you can actually
receive and store multiple records. The obvious way to do this is the usage of a complex
internal table as target of the SELECT statement. This is possible but it requires addition
TABLE between keyword INTO and the name of the internal table.

© Copyright. All rights reserved. 265


Unit 6: Complex Internal Tables

In the example, we want to read all three airports related to London and not just a single one
of them. Therefore, we leave out the keyword SINGLE after SELECT, add keyword TABLE
after INTO and use internal table airports_full as target of the SELECT statement.
The example uses an explicit field list after FIELDS that matches the columns of internal table
airports_full. Of course, you can also use FIELDS *, INTO CORRESPONDING FIELDS OF
TABLE, and alias names in the field list.

Figure 157: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE

This example uses FIELDS * instead of an explicit field list and INTO CORRESPONDING
FIELDS OF TABLE instead of INTO TABLE.
As the row type of internal table airports contains only two components AirportID and Name,
only the fields with the same name are read from the database.

Figure 158: Inline Declaration after INTO TABLE

If you use DATA( ) in a SELECT statement after addition INTO TABLE, you inline declare an
internal table. The row type of this internal table is derived from the FIELDS clause. For table

266 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

fields and view elements an alias name is optional. For expressions in the FIELDS clause, an
alias name is mandatory if the INTO clause contains an inline declaration.

Note:
Inline declarations of internal tables are only supported after INTO TABLE. You
cannot use inline declarations after INTO CORRESPONDING FIELDS OF TABLE.

Note:
Inline-declared internal tables are always standard tables without a key. You
cannot declare sorted or hashed tables using inline declarations. This can cause
performance problems if you fill the internal table with many rows and use key
access a lot.

Figure 159: Combining Results From Several SELECTs (Unions)

When you are reading multiple records from the database, some special SQL techniques
become particularly interesting. One of these techniques is the UNION directive to combine
the results of several SELECT statements.
The figure illustrates the combination of two SELECT results:
The first SELECT result reads ID and NAME of all carriers with CURRENCY_CODE = 'GBP'. The
second SELECT reads ID and NAME of all airports with CITY = 'London'. The first SELECT
returns one record, the second SELECT returns three records. Instead of retrieving these
results separately, they are combined into one result with four records. It is important to point
out that this happens inside the database.
A prerequisite for this technique is, of course, that the two results are compatible with each
other, that is, that they have the same number of fields, the same field names. It is beneficial,
though not necessary, that the types of the fields are also the same.

© Copyright. All rights reserved. 267


Unit 6: Complex Internal Tables

Figure 160: Example: UNION ALL of Two SELECTs

The ABAP SQL syntax for this example consists of two SELECT statements. Each SELECT
statement has its own FROM clause, FIELDS clause, and WHERE clause, but there is only one
INTO clause at the very end. The two SELECT statements are connected by keywords UNION
ALL.

Note:
With UNION instead of UNION ALL, the database would look for and eliminate
duplicates before returning the result. We use UNION ALL to avoid this
unnecessary additional load on the database.

Both field lists consist of three elements, the first and second element have identical alias
names in both FIELDS clauses. The third field does not need an alias because the field name is
the same in both CDS Views.

Note:
The first element in FIELDS is a literal text that allows us to distinguish between
Airlines and Airports in the combined result.

Try It Out: Internal Tables in ABAP SQL


1. As in the first exercise of this course, create a new global class that implements interface
IF_OO_ADT_CLASSRUN.

2. Copy the following code snippet to the implementation part of method


if_oo_adt_classrun~main( ):

TYPES: BEGIN OF st_airport,


airportid TYPE /dmo/airport_id,
name TYPE /dmo/airport_name,
END OF st_airport.

268 © Copyright. All rights reserved.


Lesson: Working with Complex Internal Tables

TYPES tt_airports TYPE STANDARD TABLE OF st_airport


WITH NON-UNIQUE KEY airportid.

DATA airports TYPE tt_airports.

* Example 1: Structured Variables in SELECT SINGLE ... INTO ...


**********************************************************************

DATA airport_full TYPE /DMO/I_Airport.

SELECT SINGLE
FROM /DMO/I_Airport
FIELDS AirportID, Name, City, CountryCode
WHERE City = 'Zurich'
INTO @airport_full.

out->write( `-------------------------------------` ).
out->write( `Example 1: SELECT SINGLE ... INTO ...` ).
out->write( data = airport_full
name = `One of the airports in Zurich (Structure):` ).

* Example 2: Internal Tables in SELECT ... INTO TABLE ...


**********************************************************************

DATA airports_full TYPE STANDARD TABLE OF /DMO/I_Airport


WITH NON-UNIQUE KEY AirportID.

SELECT
FROM /DMO/I_Airport
FIELDS airportid, Name, City, CountryCode
WHERE City = 'London'
INTO TABLE @airports_full.

out->write( `------------------------------------` ).
out->write( `Example 2: SELECT ... INTO TABLE ...` ).
out->write( data = airports_full
name = `All airports in London (Internal Table):` ).

* Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF TABLE


**********************************************************************

SELECT
FROM /DMO/I_Airport
FIELDS *
WHERE City = 'London'
INTO CORRESPONDING FIELDS OF TABLE @airports.

out-
>write( `----------------------------------------------------------
` ).
out->write( `Example 3: FIELDS * and INTO CORRESPONDING FIELDS OF
TABLE` ).
out->write( data = airports
name = `Internal Table AIRPORTS:` ).

* Example 4: Inline Declaration


**********************************************************************

SELECT
FROM /DMO/I_airport
FIELDS AirportID, Name AS AirportName
WHERE City = 'London'
INTO TABLE @DATA(airports_inline).

© Copyright. All rights reserved. 269


Unit 6: Complex Internal Tables

out-
>write( `----------------------------------------------------------
` ).
out->write( `Example 4: Inline Declaration after INTO TABLE` ).
out->write( data = airports_inline
name = `Internal Table AIRPORTS_INLINE:` ).

** Example 4: ORDER BY and DISTINCT


***********************************************************************
*
* SELECT
* FROM /DMO/I_Airport
* FIELDS DISTINCT CountryCode
* ORDER BY CountryCode
* INTO TABLE @DATA(countryCodes).
*
* out->write( countryCodes ).

* Example 5: UNION (ALL)


**********************************************************************

SELECT FROM /DMO/I_Carrier


FIELDS 'Airline' AS type, AirlineID AS Id, Name
WHERE CurrencyCode = 'GBP'

UNION ALL

SELECT FROM /DMO/I_Airport


FIELDS 'Airport' AS type, AirportID AS Id, Name
WHERE City = 'London'
* ORDER BY type, Id
INTO TABLE @DATA(names).

out->write( `----------------------------------------------` ).
out->write( `Example 5: UNION ALL of Airlines and Airports ` ).
out->write( data = names
name = `ID and Name of Airlines and Airports:` ).

3. Press CTRL + F3 on your keyboard to activate the class and F9 to execute the console
app.

4. Analyze the console output. Debug the program, play around with the source code to get
familiar with the concepts.

LESSON SUMMARY
You should now be able to:
● Fill complex internal tables with data
● Access the content of complex internal tables
● Use complex internal tables in ABAP SQL

270 © Copyright. All rights reserved.


Unit 6

Learning Assessment

1. Which of the following statements is true for a standard internal table?


Choose the correct answer.

X A The key is always unique

X B The key is always non-unique

X C You can choose whether the key should be unique or non-unique

2. The type tt_table is defined as follows: TYPES tt_table TYPE STANDARD TABLE OF
st_connection WITH NON-UNIQUE KEY carrier_id connection_id. Which DATA statement
would you use to create an internal table with this type?
Choose the correct answer.

X A DATA table TYPE tt_table.

X B DATA table TYPE TABLE OF tt_table.

X C DATA table TYPE REF TO tt_table.

3. Which of the following can you use to fill an internal table?


Choose the correct answers.

X A READ

X B VALUE #( )

X C LOOP...ENDLOOP

X D APPEND

© Copyright. All rights reserved. 271


Unit 6: Learning Assessment

4. You want to read data from two database tables so that the SELECT statement returns a
single result set that contains no duplicate entries. Which of the following techniques
would you use?
Choose the correct answer.

X A LEFT OUTER JOIN

X B UNION

X C INNER JOIN

X D UNION ALL

272 © Copyright. All rights reserved.


UNIT 7 Database Updates Using
Business Objects

Lesson 1
Analyzing a Business Object 275

Lesson 2
Using the Entity Manipulation Language 280
Exercise 10: Modify Data Using EML 287

UNIT OBJECTIVES

● Analyze a Business Object


● Implement an EML Statement

© Copyright. All rights reserved. 273


Unit 7: Database Updates Using Business Objects

274 © Copyright. All rights reserved.


Unit 7
Lesson 1
Analyzing a Business Object

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Analyze a Business Object

Analyzing an RAP Business Object

Figure 161: RAP Business Objects

In the ABAP RESTful Application Programming model (RAP), a business object defines a
particular entity, such as a travel agency. Its definition has two parts; a CDS view, which
defines the structure of the object or, in other words, the fields that it contains, and a behavior
definition, which describes what you can do with the business object.
The behavior definition specifies which of the standard operations, create, update, delete are
allowed. It can also contain the definition of validations, determinations, and actions.
Validations check that the data is correct when you create or update a record. Determinations
modify instances of business objects based on trigger conditions. Actions are non-standard
operations which you use to provide customized, business-logic-specific behavior. Approving
a purchase order or canceling a flight are activities that you would implement as an action.
The behavior implementation consists of one or more ABAP classes. Here the validations,
determinations, and actions are implemented. When it comes to the standard operations,
RAP distinguishes two implementation scenarios: In the unmanaged implementation
scenario, create, update, and delete are implemented in the behavior implementation. In the
managed implementation scenario the RAP runtime takes care of them.
RAP business objects are commonly used in generated Fiori Elements apps or Web APIs.
However, you can also access them from ABAP coding using Entity Manipulation Language

© Copyright. All rights reserved. 275


Unit 7: Database Updates Using Business Objects

(EML). This is a set of ABAP statements that allows you to create, read, update, and delete
data using business objects. When you create business objects using RAP, you will have to
implement its application-specific behavior. You use EML in this context to access the
application data.

Figure 162: CDS View Entity /DMO/R_AgencyTP

In this unit, you will create a class that modifies travel agency data. The view entity contains
the key field AgencyID and various other fields containing information about the travel
agency.

Behavior Definition and Implementation

Figure 163: Behavior Definition and Implementation

There are two parts to the behavior of a business object: the behavior definition and the
behavior implementation. The behavior definition contains information about what the
business object can do, while the behavior implementation contains the actual coding that the
system executes.
managed implementation in class <class> unique

276 © Copyright. All rights reserved.


Lesson: Analyzing a Business Object

The behavior implementation is an ABAP class. You declare the class in the behavior
definition in the statement managed implementation in class <class> unique. The actual
coding of the behavior implementation is contained in a local class within the global class that
you specify.

Animation
For more information on this topic please view the animation in the lesson
Analyzing a Business Object in your online course.

Figure 164: Behavior Definition

A behavior definition is an essential component of a business object. It describes which of the


standard operations are allowed, for example create, update, delete. It also defines checks
(validations) that are performed when you create or change data.
The example here is the behavior definition for the travel agency. At the beginning of the
definition, you can see the name of the CDS view we just looked at, and that there is an alias
defined for it. This is important, since it is the alias name that you use to address the entity
using EML.
The behavior definition also links the CDS entity to the database table in which the data is
stored. In this case, the business object uses two tables: one for active data and one for drafts
(data that is incomplete and has not been checked). There is also information that is relevant
for locking the data, authorization checks, and concurrency control. We are not going to look
at this information in depth - you just need to know that the RAP runtime can take care of
these issues. You can also generate CDS entities and behavior definitions based on the
definition of a database table and, in this case, locking, authorization checks, and concurrency
controls are dealt with automatically.

© Copyright. All rights reserved. 277


Unit 7: Database Updates Using Business Objects

Figure 165: Behavior Implementation

The global class of the behavior implementation (also known as a behavior pool) is just an
empty class definition with the special addition FOR BEHAVIOR OF followed by the name of
the behavior definition. The actual implementation of the behavior definition is a local class
within the global class definition. You access the class by clicking the Local Types tab.
The behavior implementation contains code that is specific to the business object, for
example, the implementation for validations, determinations, and actions. Whether it also
contains code for the standard operations (create, update, delete, and lock) depends on the
details of the behavior definition. The behavior implementation for our business object does
not contain code for the standard operations. This is because the business object uses the
managed implementation type in which the RAP runtime deals with the standard operations.

Figure 166: Validations

A validation is a check that the RAP runtime performs when data is changed. Here, the
validation is always performed when a new record is created (trigger create;) If an existing
record is changed, the validation is only performed if the Name field has been changed
(trigger field Name;).
Validations are defined in the behavior definition. For each validation, there is a corresponding
method in the behavior implementation.

278 © Copyright. All rights reserved.


Lesson: Analyzing a Business Object

LESSON SUMMARY
You should now be able to:
● Analyze a Business Object

© Copyright. All rights reserved. 279


Unit 7
Lesson 2
Using the Entity Manipulation Language

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Implement an EML Statement

Using Entity Manipulation Language

Figure 167: Entity Manipulation Language

EML consists of statements that you can use to manipulate the data of a business object. You
use the READ ENTITIES statement to read data; for all other operations, you use the MODIFY
ENTITIES statement with the corresponding addition UPDATE, CREATE, or DELETE.

Note:
You can only use the CREATE, UPDATE, and DELETE operations if the behavior
definition of the business object contains the corresponding use create, use
update, or use delete directive. Trying to use a prohibited operation causes a
syntax error.

280 © Copyright. All rights reserved.


Lesson: Using the Entity Manipulation Language

Figure 168: Reading Data

To read data from a business object, you use the READ ENTITIES statement. The statement
has two important parameters: one internal table containing the keys of the data that you
want to read and another containing the results of the query.
These internal tables have special data types called derived behavior definition types. The
system creates them automatically when a developer creates a behavior definition and they
contain some or all of the fields of the business object along with further fields that control
how the system processes a particular request. You declare the internal tables using the new
addition TYPE TABLE FOR <operation> in the DATA statement.

Figure 169: Derived Types for Read Operations

The type TABLE FOR READ IMPORT contains the key field or fields of the business object. The
%control structure is a generated structure that indicates which fields of the business object
are actually used in the current operation. In our example, the system fills the structure
automatically and you do not have to worry about it.
The type TABLE FOR READ RESULT contains all of the fields of the business object. This table
contains the result set after the read statement has been executed.

© Copyright. All rights reserved. 281


Unit 7: Database Updates Using Business Objects

Figure 170: Filling the Read Import Table

The read import table contains a column for each key field of the business object, in this case,
agencyID. To read a particular agency, you add a row to the internal table containing its key.
As well as the key field or fields, the table contains the columns %is_draft and %control. With
%is_draft you can specify whether you want to read draft data or active data. The %control
structure is used to specify which fields are to be read.

Note:
In our example, we only read active data and the %control structure is filled by the
framework, based on the field list after addition FIELDS.

Figure 171: Identifying the Entity to be Manipulated

When you process a business object, using the READ ENTITIES OF or MODIFY ENTITIES OF
statement, you must first specify the name of the behavior definition. This is followed by
keyword ENTITY and the name of the entity with which you want to work. If the entity has a
alias name, you should use it, here.

282 © Copyright. All rights reserved.


Lesson: Using the Entity Manipulation Language

Note:
You cannot use the alias name after addition OF. This is because the technically
speaking, you specify the name of the behavior definition at this point, not the
name of the entity.

Figure 172: READ ENTITIES Statement

The READ ENTITIES statement reads business object data according to the keys that you
pass in the WITH addition. It returns the result in the internal table in the RESULT addition. In
the statement, you can also specify which fields of the business object you need. In this
example, we have used the ALL FIELDS addition to return all of the fields. However, if you only
require a subset of the fields, you can use the variant FIELDS ( field1 field2 … ) to restrict the
amount of data that is read. Note that, unlike in a SELECT statement, the field list is not
comma-separated.

Figure 173: Result Table

The result table contains all of the fields of the business object, along with the control field
%is_draft. If your READ ENTITIES statement contains the FIELDS ( f1 … fn ) variant, only the
fields that you requested will be filled. If you use the ALL FIELDS variant, the system provides
the values of all of the fields.

© Copyright. All rights reserved. 283


Unit 7: Database Updates Using Business Objects

Figure 174: Derived Type for Update

If you want to update data, you declare an internal table with TYPE TABLE FOR UPDATE. This
contains all of the fields of the business object and also the %control structure. In our variant
of the MODIFY ENTITIES statement, the system fills the %control structure automatically.

Figure 175: Filling the Update Table

Figure 176: MODIFY ENTITIES Statement

284 © Copyright. All rights reserved.


Lesson: Using the Entity Manipulation Language

The MODIFY ENTITIES statement updates data in the RAP transactional buffer. In the
UPDATE FIELDS addition, you specify which fields should be changed. In the WITH addition,
you pass the internal table containing the data that you want to update.
When you use EML outside the business object, you must use the COMMIT ENTITIES
statement to trigger the RAP save sequence and persist the data in the database.

Note:
Later in this course we will use EML inside the behavior implementation. Inside the
behavior implementation it is neither necessary nor allowed to trigger the commit
with COMMIT ENTITIES.

© Copyright. All rights reserved. 285


Unit 7: Database Updates Using Business Objects

286 © Copyright. All rights reserved.


Unit 7
Exercise 10
Modify Data Using EML

1. Open the data preview of table /DMO/AGENCY and note any value of AGENCY_ID. This is
the record that you will change using EML.

2. Create a new ABAP class called ZCL_##_EML, where ## is your group number. Ensure that
the class implements the interface IF_OO_ADT_CLASSRUN.

3. In the method IF_OO_ADT_CLASSRUN~MAIN, declare an internal table with the correct


derived type for updating the business object /DMO/R_AgencyTP. Fill it with a single line
containing the AGENCY_ID that you noted in the first step and a new value for the field
NAME.

4. Modify the data, ensuring that only the field NAME is changed. Commit the changes.

5. Check whether your changes have been applied in table /DMO/AGENCY, yet.

6. Add statement COMMIT ENTITIES to your code to commit the changes.

7. Check that after the execution of the COMMIT ENTITIES statement your changes have
been applied in table /DMO/AGENCY.

© Copyright. All rights reserved. 287


Unit 7
Solution 10
Modify Data Using EML

1. Open the data preview of table /DMO/AGENCY and note any value of AGENCY_ID. This is
the record that you will change using EML.
a) Press Ctrl + Shift + A to open the Open ABAP Development Object dialog box.

b) Enter /DMO/AGENCY. There are several hits, to open the object with the Database Table
type, double-clicking it.

c) Press F8 to open the data preview.

d) Note down any single value from the column AGENCY_ID.

2. Create a new ABAP class called ZCL_##_EML, where ## is your group number. Ensure that
the class implements the interface IF_OO_ADT_CLASSRUN.
a) Choose File → New → ABAP Class.

b) Enter the name of your package in the Package field. In the Name field, enter the name
ZCL_##_EML, where ## is your group number. Enter a description.

c) In the Interfaces group box, choose Add.

d) Enter IF_OO_ADT_CLASSRUN. When the interface appears in the hit list, double-click it
to add it to the class definition.

e) Choose Next.

f) Select your transport request and choose Finish.

3. In the method IF_OO_ADT_CLASSRUN~MAIN, declare an internal table with the correct


derived type for updating the business object /DMO/R_AgencyTP. Fill it with a single line
containing the AGENCY_ID that you noted in the first step and a new value for the field
NAME.
a) Navigate to the method IF_OO_DAT_CLASSRUN~MAIN and enter the following code
(replace the values agencyID and Name with your own:

DATA update_tab TYPE TABLE FOR UPDATE /DMO/R_AgencyTP

update_tab = VALUE #( ( agencyID = '070001' Name = 'MODIFIED


Agency' ) ).

4. Modify the data, ensuring that only the field NAME is changed. Commit the changes.
a) Enter the following code in the method implementation.

MODIFY ENTITIES OF /DMO/R_AgencyTP


ENTITY /DMO/Agency
UPDATE FIELDS ( name )
WITH update_tab.

288 © Copyright. All rights reserved.


Lesson: Using the Entity Manipulation Language

5. Check whether your changes have been applied in table /DMO/AGENCY, yet.
a) Proceed as described in step 1. You should find that your change has not been applied
in the column NAME because you have not committed the changes, yet.

6. Add statement COMMIT ENTITIES to your code to commit the changes.


a) Navigate to the method IF_OO_DAT_CLASSRUN~MAIN.

b) After the MODIFY ENTITIES statement, enter the following code:

COMMIT ENTITIES.

7. Check that after the execution of the COMMIT ENTITIES statement your changes have
been applied in table /DMO/AGENCY.
a) Proceed as described in step 1. Ensure that your change has been applied in the
column NAME.

© Copyright. All rights reserved. 289


Unit 7: Database Updates Using Business Objects

LESSON SUMMARY
You should now be able to:
● Implement an EML Statement

290 © Copyright. All rights reserved.


Unit 7

Learning Assessment

1. In our scenario, what is coded in a behavior implementation?


Choose the correct answers.

X A Validations

X B Determinations

X C Update

2. In the READ ENTITIES statement, you use an internal table with a special type (TYPE
TABLE FOR READ RESULT). How is this type created?
Choose the correct answer.

X A The developer of the business object creates it as a global type.

X B The developer of the business object creates it in the behavior implementation.

X C The system creates it automatically.

© Copyright. All rights reserved. 291


Unit 7: Learning Assessment

292 © Copyright. All rights reserved.


UNIT 8 RESTful Application
Programming

Lesson 1
Introducing the ABAP RESTful Application Programming Model (RAP) 295

Lesson 2
Exploring the Architecture of RAP 296
Exercise 11: Create Data Elements 303
Exercise 12: Create a Database Table 305
Exercise 13: Generate the Development Objects for an OData UI Service 313

Lesson 3
Adding ABAP logic 318
Exercise 14: Validate the Semantic Key 329
Exercise 15: Validate the Airline 333
Exercise 16: Validate the Airport Codes 337
Exercise 17: Determine the Cities and Countries 345

Lesson 4
Improving the User Experience 349
Exercise 18: Adjust the UI of your app 353
Exercise 19: Provide Input Help 361

UNIT OBJECTIVES

● Describe the process to develop an OData Service with RAP


● Create a database table
● Generate the RAP Objects for an OData UI service
● Implement the behavior of a RAP Business Object
● Arrange Fields in the App
● Provide input help

© Copyright. All rights reserved. 293


Unit 8: RESTful Application Programming

294 © Copyright. All rights reserved.


Unit 8
Lesson 1
Introducing the ABAP RESTful Application
Programming Model (RAP)

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Describe the process to develop an OData Service with RAP

Overview
Watch this video to get an overview of what you will learn in this unit.

Video: Introduction to RESTful Application Programming


For more information on Introduction to RESTful Application Programming,
please view the video in the lesson Introducing the ABAP RESTful Application
Programming Model (RAP) in your online course.

LESSON SUMMARY
You should now be able to:
● Describe the process to develop an OData Service with RAP

© Copyright. All rights reserved. 295


Unit 8
Lesson 2
Exploring the Architecture of RAP

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Create a database table
● Generate the RAP Objects for an OData UI service

Creating The Data Model

Figure 177: Developing a Simple RAP Application

Example Data Model

Figure 178: Example Data Model

The data model in this example is very simple - there is a single database table that contains
details of flight connections - an airline, flight number, details of the departure airport and the
destination.

Note:
Not included in the figure are additional fields that the RAP runtime needs in order
to manage concurrency control. We will look at these a little later on.

296 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

Let's see how to define a database table.

Animation
For more information on this topic please view the animation in the lesson
Exploring the Architecture of RAP in your online course.

Figure 179: Creating a Database Table

To create a database table, choose File → New → Other. A dialog box appears.
Type Database table into the filter box. ADT narrows down the list of objects that you can
select.
Double-click the Database Table entry to create the table.

Figure 180: Basic Table Attributes

When you create a table, you must give it a name and assign it to a package.
In the Basic Table Attributes figure, the prefix Z stands for the customer namespace and A for
active table. This is the table in which saved data is stored. Later on, there will be a similar
table ZDCONNECTION, in which D stands for draft data. This will allow users to store
incomplete data and to resume processing it at a later date.
Choose Next. ADT prompts you for a transport request. Choose a suitable request and
choose Finish.

© Copyright. All rights reserved. 297


Unit 8: RESTful Application Programming

Figure 181: Table Definition

In the table definition, you specify the names and data types of each of the columns of the
table. To do this, you use the notation field_name : data_type ;.
The data type can be a built-in ABAP Dictionary type - for this, the notation is abap.data_type.
If the data type is incomplete, you provide the length in parentheses after the data type - for
example, abap.char(10). For numeric types with a fixed number of decimal places you would
write, for example, abap.dec(15,2). This defines a column of type DEC with 15 digits including
two decimal places.

Figure 182: Data Element

If you do not use a built-in ABAP Dictionary type to specify the type of a table column, use a
data element instead. Data elements are ABAP Dictionary objects that define the type of a
single field such as UUID, or airline code. Data elements contain not only a technical type
description but also semantic information such as field labels. If you use data elements to
define the types of the table columns, the system can use the field labels automatically on the
generated user interface.
The data element in the Data Element figure describes the airline field. It is a character field
with length 3; the system will use the field labels automatically on the generated UI.

298 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

Figure 183: Domain

The technical type of a data element is usually specified by a domain. Here you can see that
the domain for an airline code defines a character field with length 3 characters.

Figure 184: Data Element /DMO/CITY

The data element /DMO/CITY describes the data type for the columns city_from and city_to
of the database table. However, its field label - the text that will appear in the user interface - is
just the word "city". This will make it impossible to distinguish which city is the departure city
of the flight, and which is the destination city.
To improve the user experience, it is better not to use the data element /DMO/CITY in this
case. Instead, you create a new data element for the departure city and another for the
destination and define the corresponding field labels in each case. As well as the semantic
information, you must specify a data type for the new data elements. You do this by assigning
a domain. Here, you can re-use the domain /DMO/CITY, since departure city and destination
city should have the same technical attributes.

© Copyright. All rights reserved. 299


Unit 8: RESTful Application Programming

Figure 185: Creating the Data Element

To create a new data element, choose File → New → Other, then type data element into the
Filter Text field. Enter a package name and the name of the data element, then choose Next.
Select a transport request and choose Finish.
You must then specify a data type for the data element. This should be a domain - the
example re-uses the existing domain /DMO/CITY. Note that both data elements use the same
domain. This means that if someone subsequently changes the length of the domain, the
change applies to all data elements that use it.
Finally, you enter short, medium, and long field labels, and a label that is used for column
headings. Later on, when you generate the Fiori Elements app, the system will use these texts
automatically.

Figure 186: Table Key

Each table that you define must have a primary key. This is a sequence of fields at the
beginning of the table description that identifies each entry in the table uniquely.
The first field in the table (and therefore also the first field in the key definition) must be the
client field, and this must have the data type abap.clnt. Furthermore, it is convenient for our
example to use a UUID for the unique key. If you use the data element sysuuid_x16 to specify
the type of this field, you can let the RAP runtime assign the UUID automatically when you
create a new record.

300 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

Figure 187: Fields for Administration and Concurrency Control

For traceability reasons it is recommended to store some administrative information with the
data, like, for example, the user that created or changed the data and timestamps for the
creation and the last change. The database table that you create should contain the fields
displayed in the figure.

Note:
These fields are mandatory for the generator we are going to use later. For that
generator to work properly the fields also have be defined with the data types
listed here.

Especially fields local_last_changed_at and last_changed_at are not only administrative fields.
In RAP they are also used for concurrency control.
Because RESTful applications are stateless, data consistency cannot be ensured by exclusive
locks alone. RAP uses a mixture of exclusive locks and ETags to avoid data inconsistencies.
An ETag is a field that changes its value whenever a data set is updated. By comparing the
value of the ETag field, the framework can ensure that a data set has not been changed since
it was read the last time. Timestamps of the last change make perfect ETag fields.

Figure 188: Activating the Table

© Copyright. All rights reserved. 301


Unit 8: RESTful Application Programming

When you activate a database table in ADT, the system creates the corresponding physical
table in the database. Once you have done this, you will be able to generate the additional
objects that you need for your app automatically.

302 © Copyright. All rights reserved.


Unit 8
Exercise 11
Create Data Elements

1. Create a new data element called z##_city_from.

2. Use the domain /dmo/city to specify the type of the data element.

3. For each of the texts (short, medium, long, heading), enter a suitable text to describe the
departure city.

4. Activate the data element.

5. Create another data element called Z##_CITY_TO. For the data type, use the
domain /dmo/city again. For the field labels, use the word To.

© Copyright. All rights reserved. 303


Unit 8
Solution 11
Create Data Elements

1. Create a new data element called z##_city_from.


a) Choose File → New → Other.

b) Type Data e into the filter field. The system reduces the hit list to Data Element.

c) Double-click Data Element.

d) Ensure that your package is set to ZS4D400_##. Enter the name Z##_CITY_FROM and
a description. Choose Next.

e) Select your transport request and choose Finish.

2. Use the domain /dmo/city to specify the type of the data element.
a) In the Type Name field, enter /dmo/city.

3. For each of the texts (short, medium, long, heading), enter a suitable text to describe the
departure city.
a) Enter Departure in the relevant fields.

4. Activate the data element.


a) Choose Ctrl + F3.

5. Create another data element called Z##_CITY_TO. For the data type, use the
domain /dmo/city again. For the field labels, use the word To.
a) Repeat the exercise from step 1 to 4 using the data element name Z##_CITY_TO and
the field label Destination instead of Departure.

304 © Copyright. All rights reserved.


Unit 8
Exercise 12
Create a Database Table

In this series of exercises, you will create a Fiori Elements app for managing flight
connections. The first step is to create the database table that will store the data.

1. Create a new database table called Z##ACONN.

2. Enter the following list of fields between the curly brackets:

key client : abap.clnt not null;


key uuid : sysuuid_x16 not null;
carrier_id : /dmo/carrier_id;
connection_id : /dmo/connection_id;
airport_from_id : /dmo/airport_from_id;
city_from : /dmo/city;
country_from : land1;
airport_to_id : /dmo/airport_to_id;
city_to : /dmo/city;
country_to : land1;
local_created_by : abp_creation_user;
local_created_at : abp_creation_tstmpl;
local_last_changed_by : abp_locinst_lastchange_user;
local_last_changed_at : abp_locinst_lastchange_tstmpl;
last_changed_at : abp_lastchange_tstmpl;

3. For the field city_from, replace the data element /dmo/city with your own data
element z##_city_from. For the city_to field, replace the data element /dmo/city
with your own data element z##_city_to.

4. Activate the table.

© Copyright. All rights reserved. 305


Unit 8
Solution 12
Create a Database Table

In this series of exercises, you will create a Fiori Elements app for managing flight
connections. The first step is to create the database table that will store the data.

1. Create a new database table called Z##ACONN.


a) Choose File → New → Other.

b) In the Filter field, enter Database. The system filters the list of object types so that
only object types containing the word Database are displayed.

c) Double-click Database Table.

d) Ensure that the correct package (ZS4D400_##) is set. Enter the name Z##ACONN and a
description for your table (suggestion: Group ## Active Connections). Choose
Next.

e) Select your own transport request and choose Finish.

2. Enter the following list of fields between the curly brackets:

key client : abap.clnt not null;


key uuid : sysuuid_x16 not null;
carrier_id : /dmo/carrier_id;
connection_id : /dmo/connection_id;
airport_from_id : /dmo/airport_from_id;
city_from : /dmo/city;
country_from : land1;
airport_to_id : /dmo/airport_to_id;
city_to : /dmo/city;
country_to : land1;
local_created_by : abp_creation_user;
local_created_at : abp_creation_tstmpl;
local_last_changed_by : abp_locinst_lastchange_user;
local_last_changed_at : abp_locinst_lastchange_tstmpl;
last_changed_at : abp_lastchange_tstmpl;

3. For the field city_from, replace the data element /dmo/city with your own data
element z##_city_from. For the city_to field, replace the data element /dmo/city
with your own data element z##_city_to.
a) The definition of the city_from and city_to fields should now look like the following:
city_from : z##_city_from;andcity_to : z##_city_to;.

4. Activate the table.


a) Choose Ctrl + F3.

306 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

Generating Additional Development Objects

Figure 189: Developing a Simple RAP Application

In this section, we will learn how to generate the additional objects.

Generating Additional Objects


We have just defined a database table to hold our data, but the app that we are going to create
needs more objects than just this table. We can generate these objects using a wizard in ADT.

Figure 190: Generating Additional Objects

The generated objects contain all of the information that is necessary to provide a working
app with create, read, update, and delete capability. Later on, we will also adjust and extend
some of these objects to change the appearance of the user interface and to implement some
checks and calculations.
Watch this video to learn how to generate additional objects.

Video: Generating Additional Objects


For more information on Generating Additional Objects, please view the video in
the lesson Exploring the Architecture of RAP in your online course.

© Copyright. All rights reserved. 307


Unit 8: RESTful Application Programming

Figure 191: Starting the Generator

To start the object generator, right-click the table name in the Project Explorer and choose
Generate ABAP Repository Objects. The wizard starts and you must enter a package to which
all of the new objects will be assigned. You then select the generator; for this example we are
using the ABAP RESTful Application Programming Model UI Service.

Figure 192: Data Model

In the RESTful Application Programming Model, you do not access database tables directly.
Instead, you use a CDS view entity to define the data model. At this stage, in the generator,
you enter the name of a data definition. Since you are working in the customer namespace,
the name must begin with Z or Y or a reserved namespace. A further convention is that the
letter Z or Y is followed by an underscore, then the letter R for restricted, and then another
underscore.
You also have to enter an alias name, which is used inside the generated application to
identify the entity that the data definition represents.

308 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

Figure 193: Behavior Definition

With the data mode view that you create, you can read data from the database. However, our
app should also be able to create, modify, and delete data. In order to make this possible, you
must define a behavior definition. This is linked to the data mode view and specifies which of
the create, update, and delete actions are allowed. For example, some kinds of documents
must not be altered once they have been created. In this case, you would allow the create
action, but not update or delete.
As well as specifying which of the create, update, and delete actions should be available, the
behavior definition can also contain the following kinds of definitions:
● Draft enabling
● Numbering: Automatic numbering is enabled for the UUID field
● Validations: These are checks that are carried out when the user enters data in the app
● Determinations: A determination performs a calculation to fill fields in the data record.

The generator creates the behavior definition and switches on automatic numbering for the
UUID field. If you need to use validations and determinations, you must add them by hand.
The behavior definition declares which validations and determinations exist. However, they
also need an ABAP implementation. The implementations are methods, so you therefore
need an implementation class. The naming convention for this class is to use the prefix Z or Y
for the customer namespace, followed by BP_. BP stands for behavior pool.
The behavior definition also defines the draft enabling for the entity. Based on the definition of
the data model view, the generator creates a corresponding table that will contain the draft
data. You therefore need to specify the name of the draft table at this point. The naming
convention is that for a basic table ZA<table>, the draft table should be called ZD<table>.

© Copyright. All rights reserved. 309


Unit 8: RESTful Application Programming

Figure 194: Projection

The data model and its behavior definition are a reusable implementation of a particular
business entity. The next step in the object generation is to specify the name of the service
projection. The projection contains a view with precisely the fields that are required for a
particular app, a behavior definition that specifies which of the defined behaviors should
actually be available in the app, and a metadata extension. The metadata extension contains
CDS annotations that define how the UI of the app should look.
The naming convention for the projection layer is Z_C_<name>. The projection view, behavior
projection, and metadata extension will all have the same name.

Figure 195: Service Definition and Binding

In order to expose the app, you need to create a service definition and a service binding. the
service definition specifies the projection view to be exposed in this service, the service
binding specifies the protocol to be used. In our example define an OData UI service based on
version 4 of the OData protocol.

310 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

The naming convention for the service definition is Z<name>. The naming convention for the
service binding is ZUI_<name>_O4. This indicates that the binding is for a Fiori Elements app
and that it uses version 4 of the OData protocol.

Figure 196: Summary of Objects

At the end of the wizard, the system displays a list of all of the objects that it is going to
generate. You can check your entries against the naming conventions and look out for typing
errors and, if necessary, go back and change any that are incorrect.

© Copyright. All rights reserved. 311


Unit 8: RESTful Application Programming

312 © Copyright. All rights reserved.


Unit 8
Exercise 13
Generate the Development Objects for an
OData UI Service

In this exercise you will generate the additional repository objects.


You must already have created and activated the database table Z##ACONN.

1. Start the object generator in ABAP Development Tools. Ensure that the package is set to
your own package, enter a description for the generated objects, and set the generator to
generate a UI service.

2. Name the objects as described in the table:

Object Type Object Name


Data Definition Name Z##_R_Connection

Alias Name Connection

Implementation Class ZBP_##_CONNECTION

Draft Table Name Z##DCONN

Service Projection Z##_C_Connection

Service Definition Z##_CONNECTION

Service Binding Z##_UI_Connection_O4

Binding Type OData V4 - UI

3. Generate the objects.

© Copyright. All rights reserved. 313


Unit 8
Solution 13
Generate the Development Objects for an
OData UI Service

In this exercise you will generate the additional repository objects.


You must already have created and activated the database table Z##ACONN.

1. Start the object generator in ABAP Development Tools. Ensure that the package is set to
your own package, enter a description for the generated objects, and set the generator to
generate a UI service.
a) Right-click the table name in the Project Explorer and choose Generate ABAP
Repository Objects.

b) Enter a description in the Description field.

c) In the Generator field, open the dropdown list box and select ABAP RESTful Application
Programming Model: UI Service.

d) Choose Next.

2. Name the objects as described in the table:

Object Type Object Name


Data Definition Name Z##_R_Connection

Alias Name Connection

Implementation Class ZBP_##_CONNECTION

Draft Table Name Z##DCONN

Service Projection Z##_C_Connection

Service Definition Z##_CONNECTION

Service Binding Z##_UI_Connection_O4

Binding Type OData V4 - UI

a) On the left-hand side of the dialog box, click Data Model. In the right-hand pane, enter
the Data Definition Name Z##_R_Connection and Alias Name Connection.

b) On the left-hand side of the dialog box, click Behavior. In the right-hand pane, enter the
Implementation Class ZBP_##_CONNECTION and the Draft Table Name Z##DCONN.

c) On the left-hand side of the dialog box, click Service Projection. In the right-hand pane,
enter the Name Z##_C_Connection.

314 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

d) On the left-hand side of the dialog box, click Service Definition. In the right-hand pane,
enter the Name Z##_CONNECTION.

e) On the left-hand side of the dialog box, click Service Binding. In the right-hand pane,
enter the Name Z##_UI_Connection_O4 and select the Binding Type OData V4 -
UI.

3. Generate the objects.


a) Choose Next.

b) Select the appropriate transport request and choose Finish.

© Copyright. All rights reserved. 315


Unit 8: RESTful Application Programming

Previewing the OData UI Service


Publish and Preview the Service
Using your database table and the object generator, you can generate all of the objects that
you need to get a working Fiori Elements app. The only manual step is to publish the service.

Figure 197: Publish and Preview the Service

You must publish the service before you can test the app. To do so, open the service binding
and choose Publish. Once you have done this, the entity that you created (in this case,
Connection) appears in the list of entities. Mark it and choose Preview to test the app.

Test the App

Figure 198: Test the App

When you choose Preview, a browser window opens and you can create a new flight
connection. However, the app does not implement any checks other than type checks (for
example, only digits are allowed in the Flight Number field).

316 © Copyright. All rights reserved.


Lesson: Exploring the Architecture of RAP

LESSON SUMMARY
You should now be able to:
● Create a database table
● Generate the RAP Objects for an OData UI service

© Copyright. All rights reserved. 317


Unit 8
Lesson 3
Adding ABAP logic

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Implement the behavior of a RAP Business Object

Validations

Figure 199: Developing a Simple RAP Application

Checking the Semantic Key

Figure 200: Checking the Semantic Key

318 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

As shown in the figure, in an RAP data model, the key of a database table is often made up of
the client field and a UUID field, whose value is assigned automatically by the RAP runtime
when you create a new instance of the business object. This field combination is sufficient to
ensure that the system can identify each record in the table uniquely. However, as well as this
technical key, our object also has a semantic key - in this case the combination of airline and
flight number, which must also be unique according to the business logic. In order to ensure
the uniqueness of this field combination, you must implement your own check in the form of a
validation.
You declare validations in the behavior definition of the CDS view entity, and implement them
in the behavior implementation class.

Input Checks in the App


As well as checking the semantic key, there are other checks that you need to perform. For
example, although the generated app allows you to create, read, update and delete data, it
does not yet contain any consistency checks. Consequently, you can create flight connections
for airlines that don't exist, or where the departure and destination airports are the same.

Figure 201: Input Checks in the App

To prevent this from happening, you define further validations in the behavior definition, and
implement them in the behavior implementation class.

Creating Message Texts


Before you create the validation, you must create the texts that you want to display. You do
this using a message class. A message class is a collection of up to 1000 messages that
belong to a particular application area. As shown in the figure, each text has a number which
identifies the message uniquely within the message class.

Figure 202: Creating Message Texts

To create a new message class, proceed as follows:

© Copyright. All rights reserved. 319


Unit 8: RESTful Application Programming

1. Choose File → New → Other… and type message into the filter field.

2. Double-click the Message Class entry in the hit list, then enter a package, name, and
description for the new message class. Choose Next.

3. Assign the message class to a transport request and choose Finish.

Messages can also contain placeholders, which are replaced with concrete values when the
message is displayed. Placeholders are denoted by the ampersand symbol followed by a
number. You can use up to four placeholders in each message.

Defining the Validation


To define a validation, you add a validation declaration to the behavior definition of your
business object. In this example, the validation should be performed whenever the user saves
a data record, and this could be either when they create the record or if they subsequently
change it.

Figure 203: Defining the Validation

When you define the validation in the behavior definition, a warning tells you that the
corresponding method does not exist. Use a quick fix (key combination CTRL + 1) to add the
method to the behavior implementation. The behavior implementation is a local class within
your behavior pool. The method definition contains the addition FOR VALIDATE ON SAVE,
which identifies it as the implementation of the validation. It has an importing parameter
KEYS. This is an internal table containing the keys of the created or changed objects. You use
these to read the actual data that the user has entered.
The addition FOR Connection~CheckSemanticKey links the method with the validation
CheckSemanticKey from the behavior definition. Here, Connection is the alias name of the
view entity Z_R_CONNECTION.

Figure 204: Using a Quick Fix

320 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

When you define a validation, you must also create its implementation. This is a method in the
behavior pool. The easiest way to do this is to use a quick fix. Position the cursor on the name
of the validation and press CTRL + 1. ADT proposes to create the method. Double-click the
proposal to create the method.

The Validation Process

Animation
For more information on this topic please view the animation in the lesson
Adding ABAP logic in your online course.

Note:
Some code examples in this section use SELECT statements inside of loops. This
has been done to keep the examples simple. Note that SELECTs in loops can
cause performance problems and should be avoided.

Figure 205: Validation Process

When the system triggers a validation, it calls the corresponding implementation. The
importing parameter KEYS contains the keys of the data records that have been changed. You
use the keys to read the fields of the records that you need using Entity Manipulation
Language (EML). EML is a special set of statements in ABAP that allows you to address
business objects.
Once you have read the data, you can perform the checks that you need. If the check fails, you
will need to issue an appropriate error message and, importantly, tell the RAP framework not
to write the changes to the database.

© Copyright. All rights reserved. 321


Unit 8: RESTful Application Programming

Figure 206: Reading the User Input

The first task in a validation is to read the user input. You do this using the Entity Manipulation
Language (EML) statement READ ENTITIES. The keys of the new data records are passed to
the validation using the importing parameter keys.
The fields that you need to validate the semantic key are CarrierID for the airline and
ConnectionID for the flight number. You also need the UUID field.
The code snippet uses the corresponding operator and an inline declaration for the result set.
Below, you see the equivalent code using explicitly-defined variables, which makes it easier to
understand the types that are used.

DATA read_keys TYPE TABLE FOR READ IMPORT zs4d400_r_connection.


DATA connections TYPE TABLE FOR READ RESULT zs4d400_r_connection.

read_keys = CORRESPONDING #( keys ).

READ ENTITIES OF zs4d400_r_connection IN LOCAL MODE


ENTITY Connection
FIELDS ( uuid CarrierID ConnectionID )
WITH read_keys
RESULT connections.

Once you have read the user input, you can use the values of CarrierID and ConnectionID to
see if this semantic key has already been used in another data set than the one you are
processing just now. Since the key combination could be in either the active table or the draft
table, you need to look in both, and the most efficient way to do this is with a union.

322 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

Figure 207: Validating the Key

The result set of this query should always be empty. If not, there are more records with the
same combination of CarrierID and ConnectionID, this means that the record that the user is
currently trying to create is a duplicate, and must be rejected.

Figure 208: What to Do When the Validation Fails

Figure 209: Creating the Message Object

If the combination of carrier ID and connection ID already exists, there will be an entry in the
table check_result. In this case, you must issue a message.

© Copyright. All rights reserved. 323


Unit 8: RESTful Application Programming

The first step is to create a message object. You do this using the self-reference me and
calling the method new_message( ). The parameters ID, number, and severity are mandatory.
ID is the name of the message class that contains the message; number is the message
number. Severity classifies the message as a success, information, warning, or error
message. The behavior implementation class contains a structured constant mswhose
components represent the different severity levels. In this case, you need the severity level
ms-error.
The method also has optional importing parameters v1, v2, v3, and v4. You use these to
replace placeholders with concrete values. In this example, the placeholder &1 is replaced
with the airline code, placeholder &2 is replaced with the flight number.
The result of the method call is an object reference. In the next step, you will pass the object
to the RAP runtime so that the error message is returned the OData service and displayed in
the app preview.

Figure 210: Reporting the Message

To make the RAP runtime display a message, you must report it using the reported structure.
This is an implicit changing parameter of all validation methods and is a deep structure. It
contains a component with the alias name of the business object. This component is an
internal table.
To report the message, you must do three things:

1. Add the key of the affected record to the internal table. You can do this using the field
group %tky. When you group fields like this, you can address the name of the group
instead of having to address each field individually.

2. Attach the message object to the table. You do this by assigning the object reference of
the message object to the %msg component of the internal table.

3. Bind the message to the affected field. This ensures that the field is emphasized in the
app. This, in turn, helps the user to navigate the app better. You do this using the
%element component of the internal table.

324 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

Figure 211: Reporting the Message

In this example, reported_record is a structure with the line type of the internal table reported-
connection. You fill the %tky component with the contents of the %tky field group in the data
record. This is the structure line that we used as a work area for the internal table containing
the data that the user entered. Next, you assign the message object that you created using
the new_message( ) method to the %msg component. Finally, to bind the message to the field
CarrierID, you use the structure %element. %element is a structure, and contains a
component for each element in the view entity. If you set a component to "true", the
corresponding input field will be highlighted in the app. You do this using the structured
constant if_abap_behv=>mk. This has the component on for checked/true and off for
unchecked/false.

Note:

You cannot use the global constants abap_true and abap_false at this point, as their data
types are not compatible.

Figure 212: Rejecting the Changes

As well as issuing the message, you must also tell the RAP runtime not to save the incorrect
data. To do this, you use the failed structure of the validation method. Failed is an implicit
changing parameter that is present in all validation methods.
To report a record as failed, add its field group %tky to the field group %tky of the internal
table failed-Connection.

© Copyright. All rights reserved. 325


Unit 8: RESTful Application Programming

Figure 213: Validating the Airline

The next validation checks that the airline that the user has entered actually exists. The first
step is to read the user input using the EML statement READ ENTITIES. This time, you only
need to read the field CarrierID.

Figure 214: Does the Airline Exist?

The SELECT SINGLE statement reads data using the CDS view entity /dmo/i_carrier and
checks whether the given airline exists. If it does, the value of the global constant abap_true
('X') is placed in the field exists. If exists is initial following the SELECT statement, you must
issue a message, report it, and add the record to the failed structure as you did in the previous
example.

326 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

Figure 215: Validating the Origin and Destination Airports

Figure 216: Are the Airports the Same?

If the departure and arrival airports are the same, you must issue the corresponding message
and fill the reported and failed structures. The code extract shows the relevant coding to
create the message. The coding to fill the reported and failed structures is the same as in the
previous examples.

© Copyright. All rights reserved. 327


Unit 8: RESTful Application Programming

328 © Copyright. All rights reserved.


Unit 8
Exercise 14
Validate the Semantic Key

1. Define a validation CheckSemanticKey to check that a particular flight number has not
already been used.

2. Create the implementation of the validation using a Quick Fix.

3. Use the EML READ ENTITIES statement to read the data that the user entered. Ensure
that the fields CarrierID, and ConnectionID are read. Use an inline declaration for the
result set.

4. In a loop over the data that you just read, select the UUIDs of all other data sets with the
same combination of airline ID and flight number. Use a union to address the active and
the draft tables at the same time.

Note:
Make sure you only read other data sets, that is, exclude data sets with the
same UUID from the selection.

5. If the internal table check_result contains any records create a new message with
message classZS4D400, message number 001 and severity ms-error. Pass
connection-CarrierID to parameter v1 and connection-ConnectionID to
parameter v2.

6. Declare the structure reported_record with the type LIKE LINE OF reported-
connection. Add the record to the reported structure.

7. Declare the structure failed_record with the type LIKE LINE OF failed-
connection. Add the record to the failed structure and close the open IF and LOOP
control structures.

© Copyright. All rights reserved. 329


Unit 8
Solution 14
Validate the Semantic Key

1. Define a validation CheckSemanticKey to check that a particular flight number has not
already been used.
a) In the Project Explorer, navigate to the behavior definition Z##_R_CONNECTION and
add the following line: validation CheckSemanticKey on save { create;
update; }.

b) Activate the behavior definition.

2. Create the implementation of the validation using a Quick Fix.


a) Position the cursor on the name of the validation and choose Ctrl + 1.

b) Double-click the entry Add validation....

3. Use the EML READ ENTITIES statement to read the data that the user entered. Ensure
that the fields CarrierID, and ConnectionID are read. Use an inline declaration for the
result set.
a) Enter the following code in the method implementation. Replace ## with your group
number:

READ ENTITIES OF z##_r_connection IN LOCAL MODE


ENTITY Connection
FIELDS ( CarrierID ConnectionID )
WITH CORRESPONDING #( keys )
RESULT DATA(connections).

4. In a loop over the data that you just read, select the UUIDs of all other data sets with the
same combination of airline ID and flight number. Use a union to address the active and
the draft tables at the same time.

Note:
Make sure you only read other data sets, that is, exclude data sets with the
same UUID from the selection.

a) Enter the following code in the method implementation. Replace ## with your group
number:

SELECT FROM z##aconn


FIELDS uuid
WHERE carrier_id = @connection-CarrierID
AND connection_id = @connection-ConnectionID
AND uuid <> @connection-uuid
UNION
SELECT FROM z##dconn

330 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

FIELDS uuid
WHERE carrierid = @connection-CarrierID
AND connectionid = @connection-ConnectionID
and uuid <> @connection-uuid

INTO TABLE @DATA(check_result).

5. If the internal table check_result contains any records create a new message with
message classZS4D400, message number 001 and severity ms-error. Pass
connection-CarrierID to parameter v1 and connection-ConnectionID to
parameter v2.
a) Enter the following code in the method implementation:

IF check_result IS NOT INITIAL.

DATA(message) = me->new_message(
id = 'ZS4D400'
number = '001'
severity = ms-error
v1 = connection-CarrierID
v2 = connection-ConnectionID
).

6. Declare the structure reported_record with the type LIKE LINE OF reported-
connection. Add the record to the reported structure.
a) Enter the following code in the method implementation:

DATA reported_record LIKE LINE OF reported-connection.

reported_record-%tky = connection-%tky.
reported_record-%msg = message.
reported_record-%element-CarrierID = if_abap_behv=>mk-on.
reported_record-%element-ConnectionID = if_abap_behv=>mk-on.

APPEND reported_record TO reported-connection.

7. Declare the structure failed_record with the type LIKE LINE OF failed-
connection. Add the record to the failed structure and close the open IF and LOOP
control structures.
a) Enter the following code in the method implementation:

DATA failed_record like line of failed-connection.

failed_record-%tky = connection-%tky.
APPEND failed_record TO failed-connection.

ENDIF.
ENDLOOP.

© Copyright. All rights reserved. 331


Unit 8: RESTful Application Programming

332 © Copyright. All rights reserved.


Unit 8
Exercise 15
Validate the Airline

1. Define a validation CheckCarrierID to check that the airline that the user entered exists.

2. Create the implementation of the validation using a Quick Fix.

3. Use the EML READ ENTITIES statement to read the data that the user entered. Ensure
that the field CARRID is read. Use an inline declaration for the result set.

4. In a loop over the data that you just read, check that the airline exists. Use a SELECT
statement that returns the literal abap_true if the airline exists. Use the CDS View /dmo/
i_carrier as the data source of the statement.

5. If the value of exists is abap_false, create a message object with message ID


ZS4D400, number 002, severity ms-error and parameter v1 connection-CarrierID.

6. Declare the structure reported_record with the type LIKE LINE OF reported-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set, store the reference to the message object in field %msg, and link the
message to view element CarrierID. Finally, add the record to the reported structure.

7. Declare the structure failed_record with the type LIKE LINE OF failed-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set. Add the record to the failed structure and close the open IF and LOOP
control structures.

© Copyright. All rights reserved. 333


Unit 8
Solution 15
Validate the Airline

1. Define a validation CheckCarrierID to check that the airline that the user entered exists.
a) In the Project Explorer, navigate to the behavior definition Z##_R_CONNECTION and
add the following line: validation CheckCerrierID on save { create; field
CarrierID; }.

b) Activate the behavior definition.

2. Create the implementation of the validation using a Quick Fix.


a) Position the cursor on the name of the validation and choose Ctrl + 1.

b) Double-click the entry Add validation....

3. Use the EML READ ENTITIES statement to read the data that the user entered. Ensure
that the field CARRID is read. Use an inline declaration for the result set.
a) Enter the following code in the method implementation. Replace ## with your group
number:

READ ENTITIES OF z##_r_connection IN LOCAL MODE


ENTITY Connection
FIELDS ( CarrierID )
WITH CORRESPONDING #( keys )
RESULT DATA(connections).

4. In a loop over the data that you just read, check that the airline exists. Use a SELECT
statement that returns the literal abap_true if the airline exists. Use the CDS View /dmo/
i_carrier as the data source of the statement.
a) Enter the following code in the method implementation. Replace ## with your group
number:

LOOP AT connections INTO DATA(connection).

SELECT SINGLE
FROM /DMO/I_Carrier
FIELDS @abap_true
WHERE airlineid = @connection-CarrierID
INTO @DATA(exists).

5. If the value of exists is abap_false, create a message object with message ID


ZS4D400, number 002, severity ms-error and parameter v1 connection-CarrierID.
a) Enter the following code in the method implementation:

IF exists = abap_false.

334 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

DATA(message) = me->new_message(
id = 'ZS4D400'
number = '002'
severity = ms-error
v1 = connection-CarrierID
) .

6. Declare the structure reported_record with the type LIKE LINE OF reported-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set, store the reference to the message object in field %msg, and link the
message to view element CarrierID. Finally, add the record to the reported structure.
a) Enter the following code in the method implementation:

DATA reported_record LIKE LINE OF reported-connection.

reported_record-%tky = connection-%tky.
reported_record-%msg = message.
reported_record-%element-carrierid = if_abap_behv=>mk-on.

APPEND reported_record TO reported-connection.

7. Declare the structure failed_record with the type LIKE LINE OF failed-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set. Add the record to the failed structure and close the open IF and LOOP
control structures.
a) Enter the following code in the method implementation:

DATA failed_record LIKE LINE OF failed-connection.

failed_record-%tky = connection-%tky.
APPEND failed_Record TO failed-connection.

ENDIF.
ENDLOOP.

© Copyright. All rights reserved. 335


Unit 8: RESTful Application Programming

336 © Copyright. All rights reserved.


Unit 8
Exercise 16
Validate the Airport Codes

1. Define a validation CheckOriginDestination to check that the departure and arrival


airports of the flight connection are different.

2. Create the implementation of the validation using a Quick Fix.

3. Use the EML READ ENTITIES statement to read the data that the user entered. Ensure
that the fields AirportFromID and AirportToID are read. Use an inline declaration for
the result set.

4. In a loop over the data that you just read, check whether AirportFromID and
AirportToID are the same. If they are, create a message with id ZSD4D00, number 003,
and severity ms-error.

5. Declare the structure reported_record with the type LIKE LINE OF reported-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set, store the reference to the message object in field %msg, and link the
message to both airport fields. Finally, add the record to the reported structure.

6. Declare the structure failed_record with the type LIKE LINE OF failed-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set. Add the record to the failed structure and close the open IF and LOOP
control structures.

© Copyright. All rights reserved. 337


Unit 8
Solution 16
Validate the Airport Codes

1. Define a validation CheckOriginDestination to check that the departure and arrival


airports of the flight connection are different.
a) In the Project Explorer, navigate to the behavior definition Z##_R_CONNECTION and
add the following line: validation CheckOriginDestination on save
{ create; field AirportFromID, AirportToID; }.

b) Activate the behavior definition.

2. Create the implementation of the validation using a Quick Fix.


a) Position the cursor on the name of the validation and choose Ctrl + 1.

b) Double-click the entry Add validation....

3. Use the EML READ ENTITIES statement to read the data that the user entered. Ensure
that the fields AirportFromID and AirportToID are read. Use an inline declaration for
the result set.
a) Enter the following code in the method implementation. Replace ## with your group
number:

READ ENTITIES OF z##_r_Connection IN LOCAL MODE


ENTITY Connection
FIELDS ( AirportFromID AirportToID )
WITH CORRESPONDING #( keys )
RESULT DATA(connections).

4. In a loop over the data that you just read, check whether AirportFromID and
AirportToID are the same. If they are, create a message with id ZSD4D00, number 003,
and severity ms-error.
a) Enter the following code in the method implementation.

LOOP AT connections INTO DATA(connection).


IF connection-AirportFromID = connection-AirportToID.
DATA(message) = me->new_message(
id = 'ZS4D400'
number = '003'
severity = ms-error
).

5. Declare the structure reported_record with the type LIKE LINE OF reported-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set, store the reference to the message object in field %msg, and link the
message to both airport fields. Finally, add the record to the reported structure.

338 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

a) Enter the following code in the method implementation:

DATA reported_record LIKE LINE OF reported-connection.

reported_record-%tky = connection-%tky.
reported_record-%msg = message.
reported_record-%element-AirportFromID = if_abap_behv=>mk-on.
reported_record-%element-AirportToID = if_abap_behv=>mk-on.

APPEND reported_record TO reported-connection.

6. Declare the structure failed_record with the type LIKE LINE OF failed-
connection. Fill the fields in fields group %tky with the corresponding values of the
current data set. Add the record to the failed structure and close the open IF and LOOP
control structures.
a) Enter the following code in the method implementation:

DATA failed_record LIKE LINE OF failed-connection.

failed_record-%tky = connection-%tky.
APPEND failed_record TO failed-connection.

ENDIF.
ENDLOOP.

© Copyright. All rights reserved. 339


Unit 8: RESTful Application Programming

Determinations

Figure 217: Developing a Simple RAP Application

In this section, you will learn how to complete the data using determinations.

Determine Cities Based on Airport Codes


In the example app, the flight connection entity contains a departure airport, city, and
country, and an arrival airport, city, and country. While it would be possible to force the user
to enter all of this information, it is better in terms of user experience and data consistency to
have the user enter only the airport codes and for the app to read the corresponding city and
country information from the database. You can perform this kind of task in a RAP application
using a determination.

Figure 218: Determine Cities Based on Airport Codes

You will first implement the determination. Afterwards, you will learn how to deactivate input
for the fields that will be filled automatically.

Defining the Determination


You define a determination in the behavior definition of a business object. The determination
here is called getCities, it will be called whenever the business object is saved and at least one
of the AirportFromID and AirportToID fields has changed. You can use a quick fix in the
behavior definition to create the corresponding method in the behavior implementation.

340 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

Figure 219: Defining the Determination

The Determination Process


Let's explore each step of the determination process.

Figure 220: The Determination Process

When the system triggers a determination, it calls the corresponding implementation. The
importing parameter KEYS contains the keys of the data records that have been changed. In
the determination method, you use EML to read the data based on the keys in exactly the
same way that you did in the validations. However, in a determination, you also manipulate
the data in the method and you must consequently update the data held by the RAP
framework using the EML statement UPDATE.

Animation
For more information on this topic please view the animation in the lesson
Adding ABAP logic in your online course.

Note:
Some code examples in this section use SELECT statements inside of loops. This
has been done to keep the examples simple. Note that SELECTs in loops can
cause performance problems and should be avoided.

© Copyright. All rights reserved. 341


Unit 8: RESTful Application Programming

Figure 221: Reading the Airport Input

At the beginning of the determination you read the user input using EML. You need the
AirportFromID and AirportToID fields and will use these to complete the city and ciountry
information.

Figure 222: Reading the City and Country Information

The demonstration data model provides a CDS view entity /dmo/i_airport that you can use to
read the city and country in which a particular airport is located. The example uses the variant
of the INTO clause in which you explicitly specify the fields of the structure that you want to
fill. Remember that the changes to the data are in the work area of the internal table and that
you must return them to the table itself using the MODIFY statement.

342 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

Figure 223: Copying the Data to the Internal Table for Update

The READ ENTITIES statement returns an internal table with the derived type FOR READ
RESULT. To change the data in the transactional buffer, you need a MODIFY ENTITIES
statement. You pass the data that you want to change to this statement using an internal
table with the derived type FOR UPDATE. The data fields are identical in both types, however
the FOR UPDATE table has an additional structure called %control that contains
administrative information.
You cannot pass the connections table to the MODIFY ENTITIES statement. You therefore
need to copy your data into an appropriately-typed internal table (connections_upd) before
you perform the actual modification.

Figure 224: Updating the Transactional Buffer

To update the data with the fields that you filled in the determination, you use the MODIFY
ENTITIES statement. In it, you specify which fields should be updated in the FIELDS clause,
and pass the data in an internal table using the WITH addition. This table must have the
correct derived data type, which in this case would be TYPE TABLE FOR UPDATE
zsd4d400_r_connection.
The MODIFY ENTITIES statement can return messages, which you receive using the
REPORTED clause. You then propagate these messages to your own business object by
copying the contents of the internal table to the REPORTED structure of the determination
method.

© Copyright. All rights reserved. 343


Unit 8: RESTful Application Programming

344 © Copyright. All rights reserved.


Unit 8
Exercise 17
Determine the Cities and Countries

1. Define a determination getCities to fill the city and country fields automatically based
on the airport code that the user entered.

2. Create the implementation of the determination using a Quick Fix.

3. Read the user input using an EML READ ENTITIES statement. Read the fields
AirportFromID and AirportToID. Use an inline declaration for the result set.

4. In a loop over the data, use two SELECT statements to read the city and country data for
the two airports the user entered. Use the CDS view /DMO/I_Airport as the data source
and read the fields City and CountryCode. For AirportFromID, fill the fields
CityFrom and CountryFrom. For AirportToID, fill the fields CityTo and CountryTo.
Remember that you need the MODIFY statement to write the changes back to the internal
table.

5. Declare an internal table connections_upd with the type TABLE FOR UPDATE
z##_r_connections where ## is your group number. Copy the data from the internal
table connections to the new table connections_upd.

6. Use an EML MODIFY ENTITIES statement to update the data in the transactional buffer.
Restrict the update to the fields that you modified (CityFrom CityTo CountryFrom
CountryTo). Use the REPORTED addition to receive any messages from the statement.
Transfer any messages to the reported structure of your method.

© Copyright. All rights reserved. 345


Unit 8
Solution 17
Determine the Cities and Countries

1. Define a determination getCities to fill the city and country fields automatically based
on the airport code that the user entered.
a) In the Project Explorer, navigate to the behavior definition Z##_R_CONNECTION and
add the following line: determination GetCities on save { field
airportFromID, AirportToID; }.

b) Activate the behavior definition.

2. Create the implementation of the determination using a Quick Fix.


a) Position the cursor on the name of the determination and choose Ctrl + 1.

b) Double-click the entry Add method for determination....

3. Read the user input using an EML READ ENTITIES statement. Read the fields
AirportFromID and AirportToID. Use an inline declaration for the result set.
a) Enter the following coding in the method implementation. Replace ## with your group
number.

READ ENTITIES OF z##_r_connection IN LOCAL MODE


ENTITY Connection
FIELDS ( AirportFromID AirportToID )
WITH CORRESPONDING #( keys )
RESULT DATA(connections).

4. In a loop over the data, use two SELECT statements to read the city and country data for
the two airports the user entered. Use the CDS view /DMO/I_Airport as the data source
and read the fields City and CountryCode. For AirportFromID, fill the fields
CityFrom and CountryFrom. For AirportToID, fill the fields CityTo and CountryTo.
Remember that you need the MODIFY statement to write the changes back to the internal
table.
a) Enter the following coding in the method implementation:

LOOP AT connections INTO DATA(connection).

SELECT SINGLE
FROM /DMO/I_Airport
FIELDS city, CountryCode
WHERE AirportID = @connection-AirportFromID
INTO ( @connection-CityFrom, @connection-CountryTo ).

SELECT SINGLE
FROM /DMO/I_Airport
FIELDS city, CountryCode
WHERE AirportID = @connection-AirportToID
INTO ( @connection-CityTo, @connection-CountryTo ).

346 © Copyright. All rights reserved.


Lesson: Adding ABAP logic

MODIFY connections FROM connection.

ENDLOOP.

5. Declare an internal table connections_upd with the type TABLE FOR UPDATE
z##_r_connections where ## is your group number. Copy the data from the internal
table connections to the new table connections_upd.
a) Enter the following coding in the method implementation:

DATA connections_upd TYPE TABLE FOR UPDATE z##_r_connection.

connections_upd = CORRESPONDING #( connections ).

6. Use an EML MODIFY ENTITIES statement to update the data in the transactional buffer.
Restrict the update to the fields that you modified (CityFrom CityTo CountryFrom
CountryTo). Use the REPORTED addition to receive any messages from the statement.
Transfer any messages to the reported structure of your method.
a) Enter the following coding in the method implementation:

MODIFY ENTITIES OF z##_r_connection IN LOCAL MODE


ENTITY Connection
UPDATE
FIELDS ( CityFrom CountryFrom CityTo CountryTo )
WITH connections_upd
REPORTED DATA(reported_records).

reported-connection = CORRESPONDING #( reported_records-


connection ).

© Copyright. All rights reserved. 347


Unit 8: RESTful Application Programming

LESSON SUMMARY
You should now be able to:
● Implement the behavior of a RAP Business Object

348 © Copyright. All rights reserved.


Unit 8
Lesson 4
Improving the User Experience

LESSON OBJECTIVES
After completing this lesson, you will be able to:
● Arrange Fields in the App
● Provide input help

Adjusting the UI

Figure 225: Developing a Simple RAP Application

In this section, you will learn how to control field properties in the behavior definition and how
to adjust the UI in the metadata extension.

Animation
For more information on this topic please view the animation in the lesson
Improving the User Experience in your online course.

© Copyright. All rights reserved. 349


Unit 8: RESTful Application Programming

Figure 226: Adjusting the UI

When you generate a Fiori Elements app, the system creates a default user interface.
Technical fields such as the UUID, and administrative fields such as the timestamps and user
IDs are read-only and hidden by default. All other fields are displayed input-ready in the
sequence in which they appear in the CDS entity.
In the flight connection example, you can make the information easier to read by changing the
order of the fields. You can also make the fields that are filled automatically by the
determination read-only.

Figure 227: Making Fields Read-Only

You make fields read-only in the behavior definition or the behavior projection. It depends o
whether you want them to be read-only in general or only for your particular service.
In our example, we make the city and country fields read-only on the data model level because
their values should always be provided by the determination. If we kept them editable we
would have to implement a validation to make sure the cities and countries match the airport
IDs.
To define a list of fields as read-only, use the field ( readonly ) statement with a comma-
separated list of fields. You end the list with a semicolon after the last field.

350 © Copyright. All rights reserved.


Lesson: Improving the User Experience

Figure 228: Projection and Metadata Extension

Metadata extensions are standalone repository objects that contain the annotations
belonging to a particular CDS entity. The idea behind them is to make it easier to understand
both the definition of the CDS entity and the annotations by separating them. Otherwise, the
CDS definition would become very long and difficult to read.
If you want to use a metadata extension in conjunction with a CDS view, the CDS view must
contain the annotation @Metadata.allowExtensions: true. The RAP object generator
takes care of this for you and automatically generates both a metadata extension for the
projection view and the corresponding annotation in the projection view itself.

Figure 229: Important UI Annotations

There are two important UI annotations that you might need to change in the metadata
extension. The first is @UI.LineItem. This is an array in which you set the attribute position.
This determines the position of the column in the report list page of the app.
The second annotation is @UI.identification. This is, again, an array in which you also set
the attribute position. This determines the position of the field in the single object page. that is
displayed during the create or update operation.

© Copyright. All rights reserved. 351


Unit 8: RESTful Application Programming

Figure 230: Rearranging the Fields

To change the position of the fields, you assign a new value to the attribute
@UI.identification: [ { position: } ]. To rearrange the fields so that they are
displayed as in the "After" figure, you must change the position of the AirportToID field from
60 to 40, the position of the CityFrom field from 40 to 50, the position of the CountryFrom
field from 50 to 70, and so on.

352 © Copyright. All rights reserved.


Unit 8
Exercise 18
Adjust the UI of your app

1. In the behavior definition of your projection set the fields CityFrom, CityTo,
CountryFrom, and CountryTo to read-only.

2. Rearrange the fields in the app so that they appear in the following order:

10 CarrierID
20 ConnectionID
30 AirportFromID
40 AirportToID
50 CityFrom
60 CityTo
70 CountryFrom
80 CountryTo

© Copyright. All rights reserved. 353


Unit 8
Solution 18
Adjust the UI of your app

1. In the behavior definition of your projection set the fields CityFrom, CityTo,
CountryFrom, and CountryTo to read-only.
a) Open the behavior definition Z##_R_CONNECTION (where ## is your group number.

b) Enter the following code in the behavior definition. The precise position is not
important. We suggest that you place it immediately after the existing field
statement:

field ( readonly )
CityFrom,
CountryFrom,
CityTo,
CountryTo;

a) Activate the behavior definition.

2. Rearrange the fields in the app so that they appear in the following order:

10 CarrierID
20 ConnectionID
30 AirportFromID
40 AirportToID
50 CityFrom
60 CityTo
70 CountryFrom
80 CountryTo

a) Open the metadata extension Z##_C_CONNECTION where ## is your group number.


Where necessary, change the value of the annotation @UI.identification:
[ { position: } ] so that it corresponds to the value in the table.

@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Connection',
typeNamePlural: 'Connections'
}
}
annotate view ZS4D400_C_CONNECTION with

354 © Copyright. All rights reserved.


Lesson: Improving the User Experience

{
@UI.facet: [ {
id: 'idIdentification',
type: #IDENTIFICATION_REFERENCE,
label: 'Connection',
position: 10
} ]
@UI.hidden: true
UUID;

@UI.lineItem: [ {
position: 10 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 10 ,
label: ''
} ]
CarrierID;

@UI.lineItem: [ {
position: 20 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 20 ,
label: ''
} ]
ConnectionID;

@UI.lineItem: [ {
position: 30 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 30 ,
label: ''
} ]
AirportFromID;

@UI.lineItem: [ {
position: 40 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 50 ,
label: ''
} ]
CityFrom;

@UI.lineItem: [ {
position: 50 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 70 ,
label: ''

© Copyright. All rights reserved. 355


Unit 8: RESTful Application Programming

} ]
CountryFrom;

@UI.lineItem: [ {
position: 60 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 40 ,
label: ''
} ]
AirportToID;

@UI.lineItem: [ {
position: 70 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 60 ,
label: ''
} ]
CityTo;

@UI.lineItem: [ {
position: 80 ,
importance: #MEDIUM,
label: ''
} ]
@UI.identification: [ {
position: 80 ,
label: ''
} ]
CountryTo;

@UI.hidden: true
LocalLastChangedAt;
}

a) Activate the metadata extension.

356 © Copyright. All rights reserved.


Lesson: Improving the User Experience

Providing Input Help

Figure 231: Developing a Simple RAP Application

In this section, we will learn about providing value help to the users. Watch this video to learn
more.

Video: Provide Value Help


For more information on Provide Value Help, please view the video in the lesson
Improving the User Experience in your online course.

Figure 232: Providing Input Help

A feature of all of SAP's user interface solutions over the years has been value help, which
gives the user the possibility to display a list of possible values that can be entered in a field.
Typically, this is achieved by reading data from the database. In Fiori Elements, you can
provide a value help by defining a CDS View that displays the possible values and attaching it
to a field in the app.

© Copyright. All rights reserved. 357


Unit 8: RESTful Application Programming

Figure 233: CDS View ZS4D400_I_CARRIERVH

This CDS view selects data from the database table /DMO/CARRIER, which contains a list of
airlines. It returns two columns - the airline code and its name. These columns will form the hit
list of the value help.
The view also contains @UI.lineItem annotations. These define how the hit list will look on
the screen - in this case with the airline code first and its name second.

Figure 234: Attaching a Value Help to a Field

To provide a value help, you attach the view that defines the hit list to a field of your projection
view using an annotation. The system then displays the field with a value help button. When
the user clicks the button, the system reads the possible values using the view and displays
the hit list accordingly.
When the user chooses an entry from the hit list, the system must return a single value to the
field. In the annotation, you must also specify which field of the value help hit list should be
placed in the input field.

358 © Copyright. All rights reserved.


Lesson: Improving the User Experience

Figure 235: Annotating the Field

To attach the value help to the field, use the annotation


@Consumption.valueHelpDefinition. This is an array that contains an object entity.
entity has two attributes:name is the name of the CDS view that the system should use to
provide the value help, element is the name of the element of the CDS view that contains the
value that should be used when the user chooses an entry from the value help.

© Copyright. All rights reserved. 359


Unit 8: RESTful Application Programming

360 © Copyright. All rights reserved.


Unit 8
Exercise 19
Provide Input Help

1. Create a CDS View Entity called Z##_I_CarrierVH.

2. Mark the appropriate transport request and chose Next.

3. Ensure that the view contains only the fields carrier_id (with alias CarrierID) and
name (with alias Name).

4. Add @UI.lineItem annotations so that the system displays the data when the user
starts the value help.

5. Activate the CDS View Entity.

6. In the projection view Z##_C_CONNECTION (where ## is your group number) attach the
value help to the field CarrierID. Use the annotation
@Consumption.valueHelpDefinition. For the attribute name use the CDS View Entity
Z##_I_CarrierVH, and for the attribute element, use the field CarrierID.

7. Activate the data definition.

© Copyright. All rights reserved. 361


Unit 8
Solution 19
Provide Input Help

1. Create a CDS View Entity called Z##_I_CarrierVH.


a) Choose File → New → Other.

b) Type data into the filter field to restrict the number of objects offered.

c) Double-click Data Definition.

d) Ensure that the package is correct, enter the name Z##_I_CarrierVH where ## is
your group number. Enter a description and the referenced object /DMO/AIRLINE.

e) Choose Next.

2. Mark the appropriate transport request and chose Next.


a) Mark the template Define View Entity and choose Finish.

3. Ensure that the view contains only the fields carrier_id (with alias CarrierID) and
name (with alias Name).
a) Delete the fields currency_code to last_changed_at. The view definition should
now look like this:

define view entity Z##_I_CarrierVH


as select from /dmo/carrier
{
key carrier_id as CarrierID,
name as Name

4. Add @UI.lineItem annotations so that the system displays the data when the user
starts the value help.
a) Add the annotations so that your source code looks like this:

@UI.lineItem: [{position: 10 }]
key carrier_id as CarrierID,
@UI.lineItem: [{position: 20 }]
name as Name

5. Activate the CDS View Entity.


a) Choose Ctrl + F3.

6. In the projection view Z##_C_CONNECTION (where ## is your group number) attach the
value help to the field CarrierID. Use the annotation
@Consumption.valueHelpDefinition. For the attribute name use the CDS View Entity
Z##_I_CarrierVH, and for the attribute element, use the field CarrierID.

362 © Copyright. All rights reserved.


Lesson: Improving the User Experience

a) Open the data definition Z##_C_CONNECTION and add the following annotation before
the element CarrierID. Replace ## with your own group:

@Consumption.valueHelpDefinition:
[{ entity: { name: 'ZS4D400_I_CarrierVH',
element: 'CarrierID'
}
}]
CarrierID,

7. Activate the data definition.


a) Choose Ctrl + F3.

© Copyright. All rights reserved. 363


Unit 8: RESTful Application Programming

LESSON SUMMARY
You should now be able to:
● Arrange Fields in the App
● Provide input help

364 © Copyright. All rights reserved.


Unit 8

Learning Assessment

1. Which of the following can you use to specify the data type of a column in a database
table?
Choose the correct answer.

X A Domain

X B Data element

X C Local type

2. When you create a database table to generate a RAP application, you must create a client
field. Which data type must it have?
Choose the correct answer.

X A The built-in ABAP Dictionary type abap.char(3)

X B The built-in ABAP Dictionary type abap.clnt.

X C The data element MANDT.

3. Which of the following parts of a behavior definition are generated automatically?


Choose the correct answers.

X A Draft enabling

X B Validations

X C Determinations

X D Create, update, and delete operations

4. You need to display an error text. Where do you create it?


Choose the correct answer.

X A In a text pool.

X B In a global class.

X C In a message class.

© Copyright. All rights reserved. 365


Unit 8: Learning Assessment

5. When you create a validation, what does the system generate automatically?
Choose the correct answer.

X A An empty method in the local class of the behavior implementation.

X B An empty method in the global class of the behavior implementation.

X C A fully-implemented method in the local class of the behavior implementation.

X D A fully-implemented method in the global class of the behavior implementation.

6. In the validation, you use the READ ENTITIES statement to read the data entered by the
user. Which parameter of the validation method do you use to ensure that the correct data
is retrieved?
Choose the correct answer.

X A REPORTED

X B FAILED

X C KEYS

7. Where do you declare fields as read-only?


Choose the correct answer.

X A In the metadata extension

X B In the behavior implementation

X C In the behavior definition

8. What does the annotation @Consumption.ValueHelpDefiniton specify?


Choose the correct answers.

X A A list of possible entries

X B A CDS view that provides the hit list

X C A list of fields in the hit list

X D The field that provides the selected value

366 © Copyright. All rights reserved.

You might also like