Behavior Implementations
RAP / CDS / ODataintermediate

Behavior Implementations Part 1: The Behavior Pool — Handler and Saver Classes

Key takeaway

Understand the anatomy of a behavior pool: the global ZBP class, local handler and saver classes, how methods are generated from the BDEF, implicit parameters, derived types and the %-components you use in every method.

What this complete series covers

Learn Behavior Implementations in a clear, practical sequence — from the basic idea to real project use, troubleshooting, and interview-ready understanding.

Who it is for
Best for SAP consultants, developers, and learners who want a practical understanding of Behavior Implementations.
Prerequisites
Basic ABAP and ADT in Eclipse are recommended. The series explains the RAP/CDS/OData concepts as they are introduced.
Final outcome
By the end, you should be able to explain Behavior Implementations clearly, follow the main end-to-end flow, apply it in a project scenario, and troubleshoot the most common issues.
  1. Part 1: Behavior Implementations Part 1: The Behavior Pool — Handler and Saver Classes

    Understand the generated RAP behavior pool architecture: local handler methods implement interaction logic while saver logic participates in controlled persistence for scenarios th

  2. Part 2: Behavior Implementations Part 2: Determinations and Validations Without Side Effects

    Implement RAP determinations as repeatable data derivation and validations as deterministic invariant checks against transactional state, while avoiding recursion, hidden persisten

  3. Part 3: Behavior Implementations Part 3: Actions, Results and User-Facing Messages

    Implement RAP actions as explicit business commands with clear preconditions, transactional changes through EML, predictable result shapes, and field- or instance-targeted messages.

  4. Part 4: Behavior Implementations Part 4: Save Sequence, Late Numbering and Unmanaged Save

    Use RAP save phases deliberately for persistence, late key assignment, final consistency, and integration with legacy save logic without breaking the framework-controlled transaction.

  5. Part 5: Behavior Implementations Part 5: Performance, Unit Testing and Debugging

    Engineer RAP behavior for bulk requests, test it through EML and domain-unit tests, and debug with request-level evidence so one-row UI success does not hide production N+1 queries

System and release assumptions: Examples target recent SAP S/4HANA / ABAP Cloud capabilities. RAP, CDS, OData, and Fiori Elements syntax and tooling can differ by ABAP platform release.

Explanation

📌 KEY POINTS
✅ Code lives in local handler classes (interaction) and the saver (save phase).

✅ Generate methods from the BDEF with Ctrl+1.

✅ failed / reported / mapped are implicit response parameters.

📌 Use %tky everywhere — it includes %is_draft.

▶ WHAT THIS SERIES COVERS
The behavior definition says what a BO can do; the behavior implementation is the ABAP code that does the non-standard parts. This series explains the mechanics; the Managed RAP series shows them in a full build.

  • Part 1 — the behavior pool: handler and saver classes (this lesson)
  • Part 2 — determinations and validations without side effects
  • Part 3 — actions, results and user-facing messages
  • Part 4 — save sequence, late numbering and unmanaged save in the saver
  • Part 5 — performance, unit testing and debugging

━━━━━━━━━━━━━━━━━━━━
▶ THE BEHAVIOR POOL

The behavior pool is a global class, e.g. ZBP_R_PURCHREQ, declared "ABSTRACT FINAL FOR BEHAVIOR OF zr_purchreq". The global class itself is empty. All code lives in the local types include (the Local Types tab in ADT), in local classes:

  • Handler classes — "INHERITING FROM cl_abap_behavior_handler", usually one per entity (lhc_PurchaseRequest, lhc_Item). They contain the interaction-phase methods: determinations, validations, actions, functions, authorization, feature control, prechecks, and in unmanaged BOs also CRUD, read and lock.
  • Saver class — "INHERITING FROM cl_abap_behavior_saver" (lsc_…). Only needed for save-phase code: finalize, check_before_save, adjust_numbers, save / save_modified, cleanup, cleanup_finalize.

You do not create these by hand: place the cursor on the class name or a BDEF element and use the ADT quick fix (Ctrl+1).

━━━━━━━━━━━━━━━━━━━━
▶ METHOD SIGNATURES — GENERATED FROM THE BDEF

Each BDEF element produces a method with a special FOR clause:

  • "METHODS setInitialStatus FOR DETERMINE ON MODIFY IMPORTING keys FOR PurchaseRequest~setInitialStatus."
  • "METHODS validateDescription FOR VALIDATE ON SAVE IMPORTING keys FOR PurchaseRequest~validateDescription."
  • "METHODS approve FOR MODIFY IMPORTING keys FOR ACTION PurchaseRequest~approve RESULT result."
  • "METHODS get_instance_features FOR INSTANCE FEATURES IMPORTING keys REQUEST requested_features FOR PurchaseRequest RESULT result."
  • "METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION IMPORTING REQUEST requested_authorizations FOR PurchaseRequest RESULT result."

You never call these methods yourself; RAP calls them at the right time.

━━━━━━━━━━━━━━━━━━━━
▶ IMPLICIT PARAMETERS

Besides the declared ones, most methods have implicit changing parameters:

  • failed — instances that failed (with %fail-cause).
  • reported — messages per instance (%msg) or unbound (%other).
  • mapped — key mapping for new instances (%cid → key), in methods that create.

Their types are derived from the BO, so you address them per entity: failed-purchaserequest, reported-item.

━━━━━━━━━━━━━━━━━━━━
▶ DERIVED TYPES

RAP generates types for everything: "TYPE TABLE FOR CREATE zr_purchreq", "TYPE TABLE FOR READ RESULT zr_purchreq", "TYPE RESPONSE FOR FAILED zr_purchreq". You rarely declare them explicitly — inline declarations (DATA(...)) and VALUE #( ) infer them.

THE %-COMPONENTS YOU MUST KNOW

  • %tky — transactional key: the key plus %is_draft (if draft). Use it everywhere to identify instances.
  • %key — only the key fields.
  • %cid / %cid_ref — content ID of a new instance / reference to it within one request.
  • %pid — preliminary ID with late numbering.
  • %is_draft — draft (mk-on) or active instance.
  • %control — which fields were supplied (mk-on per field).
  • %param — action parameter or action result data.
  • %msg — message object; %element — field(s) to highlight; %state_area — message group; %fail-cause — reason in failed.
  • %other — messages not bound to an instance.

━━━━━━━━━━━━━━━━━━━━
▶ GOLDEN RULES FOR ALL HANDLER CODE

  1. Every method receives a table — process all rows.
  2. Read with READ ENTITIES … IN LOCAL MODE, change with MODIFY ENTITIES … IN LOCAL MODE.
  3. Use %tky, not key fields.
  4. No COMMIT, no direct DML on the BO's tables, no dialogs.
  5. Report problems via failed and reported, never by raising unhandled exceptions or MESSAGE statements.

━━━━━━━━━━━━━━━━━━━━
▶ WHAT YOU HAVE AFTER PART 1

The map of a behavior pool. Part 2 implements determinations and validations correctly.

Code example

ABAP Code
" ===== Global class (generated, stays empty) =====CLASS zbp_r_purchreq DEFINITION PUBLIC ABSTRACT FINAL FOR BEHAVIOR OF zr_purchreq.ENDCLASS.CLASS zbp_r_purchreq IMPLEMENTATION.ENDCLASS. " ===== Local Types include: handler for the root entity =====CLASS lhc_PurchaseRequest DEFINITION INHERITING FROM cl_abap_behavior_handler.  PRIVATE SECTION.    METHODS get_global_authorizations FOR GLOBAL AUTHORIZATION      IMPORTING REQUEST requested_authorizations FOR PurchaseRequest RESULT result.     METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION      IMPORTING keys REQUEST requested_authorizations FOR PurchaseRequest RESULT result.     METHODS get_instance_features FOR INSTANCE FEATURES      IMPORTING keys REQUEST requested_features FOR PurchaseRequest RESULT result.     METHODS setInitialStatus FOR DETERMINE ON MODIFY      IMPORTING keys FOR PurchaseRequest~setInitialStatus.     METHODS validateDescription FOR VALIDATE ON SAVE      IMPORTING keys FOR PurchaseRequest~validateDescription.     METHODS approve FOR MODIFY      IMPORTING keys FOR ACTION PurchaseRequest~approve RESULT result.ENDCLASS. " ===== Handler for the child entity =====CLASS lhc_Item DEFINITION INHERITING FROM cl_abap_behavior_handler.  PRIVATE SECTION.    METHODS calculateTotal FOR DETERMINE ON MODIFY      IMPORTING keys FOR Item~calculateTotal.ENDCLASS. " ===== Saver (only if save-phase code is needed) =====CLASS lsc_zr_purchreq DEFINITION INHERITING FROM cl_abap_behavior_saver.  PROTECTED SECTION.    METHODS adjust_numbers REDEFINITION.     " late numbering    METHODS save_modified  REDEFINITION.     " additional/unmanaged saveENDCLASS. " ===== Using implicit parameters and %-components =====METHOD validateDescription.  READ ENTITIES OF zr_purchreq IN LOCAL MODE    ENTITY PurchaseRequest FIELDS ( Description ) WITH CORRESPONDING #( keys )    RESULT DATA(requests).                        " derived type inferred   LOOP AT requests INTO DATA(request) WHERE Description IS INITIAL.    APPEND VALUE #( %tky = request-%tky ) TO failed-purchaserequest.      " implicit    APPEND VALUE #( %tky = request-%tky                    %msg = new_message_with_text(                             severity = if_abap_behv_message=>severity-error                             text     = 'Description is required' )                    %element-Description = if_abap_behv=>mk-on )      TO reported-purchaserequest.                                        " implicit  ENDLOOP.ENDMETHOD. " Explicit derived types, when you need them:" DATA create_tab TYPE TABLE FOR CREATE zr_purchreq." DATA read_res   TYPE TABLE FOR READ RESULT zr_purchreq." DATA failed_all TYPE RESPONSE FOR FAILED zr_purchreq.

Real project scenario

A team's first RAP BO grew into one 1,800-line handler class for all entities, with helper methods mixed in and several methods working on the first key only. Bugs appeared whenever Fiori sent more than one instance, for example in mass actions.
In a refactoring, they split the code into one handler per entity, moved reusable logic into a separate domain class, and applied the golden rules (process all rows, EML in local mode, %tky, failed/reported). The class became readable, the multi-instance bugs disappeared, and new team members could find the method for a BDEF element immediately.

Common mistakes

  • Putting code into the global class instead of the local types include.
  • One giant handler for all entities.
  • Processing only keys[ 1 ].
  • Using key fields instead of %tky, breaking draft.
  • Raising MESSAGE or unhandled exceptions instead of filling failed and reported.
  • Writing methods by hand instead of generating them from the BDEF.

Best practices

  • Generate method stubs with the ADT quick fix.
  • One handler class per entity; saver only when needed.
  • Extract larger reusable logic into separate classes called from handlers.
  • Learn the %-components; use %tky everywhere.
  • Follow the golden rules in every method and check them in code reviews.

Interview angle

Questions: "What is a behavior pool?", "What is the difference between a handler and a saver class?", "What are failed, reported and mapped?", "What is %tky?"
Strong answer: the behavior pool is a global class FOR BEHAVIOR OF the BO with local handler classes (interaction phase: determinations, validations, actions, authorization, feature control, and CRUD in unmanaged) and an optional saver class (save sequence). Methods are generated from BDEF elements. failed, reported and mapped are implicit response parameters. %tky is the key plus %is_draft, used to identify instances in draft-enabled BOs.

Practice this lesson

Quick check

1. Which statement about the structure of a behavior pool is correct?

2. When enabling draft handling for a RAP business object, which additional artifact must typically be created alongside the transactional behavior definition?

3. During implementation of the standard CREATE operation in an unmanaged RAP behavior pool, which method signature parameter is used to report newly assigned keys back to the framework?

Interview questions

1. What is a behavior pool, and what is the difference between its handler and saver classes?

Answer it in your own words first, then compare.

2. Explain %tky, %key, %cid, %pid, %control and %param. Which mistake happens when developers use key fields instead of %tky?

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics