Skip to Content

Where am I being called from......

I have a global class definition that is sub-classed either directly to a class that implements the final requirement, or to a class that adds functionality that is not required by all sub-classes which is then sub-classed to a class that implements some other final requirement.


I would like a protected method that can be redefined (so that rules out a static method) that returns a different value based upon the 'level' from which that method was called.

Lets' say we have the following:

Dictionary Class - 'A' Value required 1
Sub Class of 'A' - 'B' Value required 2
Sub Class Of 'B' - 'C' Value required 3.

In general the method in class C would look like:

If I am not being called at this level
   Result = Super->method( ).
Else.
   Result = 3.
EndIf

In Class A, result would 2 and in the dictionary method it would just be a single statement returning the result of 1.

I have tried reading the call stack - this doesn't contain the class names to enable me to tell where it came from. I've also used the Get_Relative_Name method from the cl_Abap_TypeDescr class and for global methods (ie class 'A' above) it works - I can identify the actual class name but for local classes it always returns the 'Me' name even if the method is being called from a method in class B

So - to re-iterate my question - In Abap Objects how do I tell where I am being called from ?

Thanks and regards.

Rich

ps. Sorry if I don't have the right tags. - I haven't managed to figure this all out yet!

Add comment
10|10000 characters needed characters exceeded

  • Why am I doing this ?

    I have to implement a series of custom interfaces. Each interface is encapsulated in a local class with it's own message class.

    There are a set of operations that are common to each interface such as 'Is it active', or reading and parsing the data into an internal table, creating and updating an application log etc etc. This and the messages associated with these operations are contained in the interface base class and it's own message class. This is defined in a global class ("A" above)

    Some of these interfaces update measurement documents, some don't so the functionality for this is in a class with it's own message class ("B" above).

    Then come the classes that actually implement the interfaces one class (a wheel lathe) implements measurement points so is subclassed from "B". A Diesel pump interface doesn't so is sub-classed from "A". Both of these have their own message class.

    To keep the programming structure the same I want a redefinable method (Message_Class( )) that when called returns the message class to use for the current message being output so the code is always something like:

    ls_Msg-MsgId = Message_Class( ).

    rather than

    ls_Msg-MsgId = Message_Class_wl( ). "_wl _fl etc etc

    It was a good thought......

    Oh well!

    thanks for your suggestions!

    Regards

    Rich

  • Hello,

    • I am not sure to understand the concrete meaning of "If I am not being called at this level". Is it possible to illustrate it with a little program ?
    • Trying to understand, I have created 3 "dictionary" classes (as you described) and a se38 program with 2 local subclasses

    "3" dictionary classes

    A se38 program

    REPORT  ztest_class_level.
    *----------------------------------------------------------------------*
    *       CLASS lcl_b DEFINITION
    *----------------------------------------------------------------------*
    CLASS lcl_b DEFINITION INHERITING FROM zcl_a.
      PROTECTED SECTION.
        METHODS zzmethod_protected REDEFINITION.
    ENDCLASS.                    "lcl_b DEFINITION
    *----------------------------------------------------------------------*
    *       CLASS lcl_b IMPLEMENTATION
    *----------------------------------------------------------------------*
    CLASS lcl_b IMPLEMENTATION.
      METHOD zzmethod_protected.
        rt_level = 'b'.
      ENDMETHOD.                    "zzmethod_protected
    ENDCLASS.                    "lcl_b DEFINITION
    *----------------------------------------------------------------------*
    *       CLASS lcl_c DEFINITION
    *----------------------------------------------------------------------*
    CLASS lcl_c DEFINITION INHERITING FROM zcl_b.
      PROTECTED SECTION.
        METHODS zzmethod_protected REDEFINITION.
    ENDCLASS.                    "lcl_b DEFINITION
    *----------------------------------------------------------------------*
    *       CLASS lcl_b IMPLEMENTATION
    *----------------------------------------------------------------------*
    CLASS lcl_c IMPLEMENTATION.
      METHOD zzmethod_protected.
        rt_level = 'c'.
      ENDMETHOD.                    "zzmethod_protected
    ENDCLASS.                    "lcl_b DEFINITION
    
    DATA g  TYPE            REF TO zcl_a.
    DATA gt LIKE STANDARD TABLE OF g.
    
    DATA level TYPE char1.
    
    START-OF-SELECTION.
    
      CREATE OBJECT g TYPE zcl_a.  APPEND    g  TO gt. "level 1
      CREATE OBJECT g TYPE zcl_b.  APPEND    g  TO gt. "level 2
      CREATE OBJECT g TYPE zcl_c.  APPEND    g  TO gt. "level 3
      CREATE OBJECT g TYPE lcl_b.  APPEND    g  TO gt. "level b
      CREATE OBJECT g TYPE lcl_c.  APPEND    g  TO gt. "level c
      LOOP AT gt INTO g.
    
        level =   g->zzmethod_public( ).
    
        NEW-LINE.
        WRITE level.
    
      ENDLOOP.

    Executing this program, the result is

    global-classes.jpg (302.1 kB)
    se38-list.jpg (32.0 kB)
  • Former Member

    I believe you want to determine the inheritance level, not call stack level.

    Above screenshot has lcl_two inheriting from lcl_one, and lcl_three inheriting from lcl_two.

    This information is visible in debugger but it appears debugger classes can't be used in custom programs.

    docpv.png (7.8 kB)
  • Get RSS Feed

3 Answers

  • Dec 08, 2016 at 06:05 PM

    I'm afraid there's no simple solution.

    Add comment
    10|10000 characters needed characters exceeded

    • Don't ask me why, but ABAP doesn't offer a direct way for doing that.

      After SYSTEM _CALLSTACK you might play around with strictly internal

      LOAD REPORT

      parts CONT and TRIG for static code analysis, but maybe it is better to pass the identity of the caller explicitly to the caller by offering an appropriate parameter.

  • Dec 08, 2016 at 06:03 PM

    Use function module SYSTEM_CALLSTACK, you should be able to see the full hierarchy of where the call came from.

    Add comment
    10|10000 characters needed characters exceeded

  • Dec 09, 2016 at 08:31 PM

    BTW, just a general question - why is this all implemented as local classes and not standalone classes? You should be able to extract them to standalone classes pretty easily and the one thing ABAP gives you over other languages is to declare the classes as "Friends" so they can access each other's private and protected methods and attributes.

    Messages "classes" being linked to exception class will also give you another layer of flexibility. For example, (I don't know if this will work in your case), you could always just raise your exception from where ever and CATCH it in the calling program.

    Now, I just keep getting ideas! Here is another one, in your CONSTRUCTOR for each local class, you can increment an optional counter if it is called from another of your classes. If it is not from another class and a direct call from the program, then don't increment the counter.

    This is definitely solvable with a little creativity - I don't think you need to make major programming changes, just a few strategic ones. Hope one of these sets of an idea at least!

    Add comment
    10|10000 characters needed characters exceeded

    • Hi Raghu,

      A good question. They are being implemented as local classes because they only have a single use and no static methods, whereas the base class also provides constant values to a controlling program via static methods. I was trying to implement something that does not rely on shall we say "custom programming" even as simple as it would be (ie using provided classes). The idea of a counter looks good to start with, but there is the situation (outlined above) where the "implementing" class is subclassed from 2 super classes (ie A->B->C or A->C) dependant on the functionality required so the count would be different for the same required message class. And as Horst say's above, to use the call stack you end up effectively parsing the code.

      Thanks for all your ideas though and thanks to every one who has answered.

      Regards

      Rich