ABAP Objects – Access Text from Super Class Text Symbols

By | February 10, 2013 | ABAP Objects, Tricks, Utilities | 4,592 | 9

Text Pools are great for creating language independent program. But, it create a very peculiar problem when used in ABAP objects

What is Text Symbols?

Text Symbols are part of the Text Pool. This allow you to create, your development object without hard coding the language specific literals.

For example ‘Good Morning’ in English would be ‘guten Morgen’ in German. If you don’t use Text Symbols, you need have to set these literals based on log on language. Ahh Bad design – Need to change every time a new language is required, too may conditions! Easy solution would be create your literals as Text Symbols and translate the text symbols in the required languages.

More on Text Symbols – Text Symbols on SAP Help

Problem when using in ABAP objects

In ABAP objects as well, you can use Text Symbols to distinguish your Literals out of the coding. The problem is when you create a text symbol in a Super Class, you can’t reuse that in your subclass – defeating the purpose of the ABAP objects.

Lets see by an example:
You have a ALV super class, where you set the Field catalog. This is a common and you are inheriting other subclasses for different ALVs. To make your program language independent, you have used the Text Symbols. So far so good. Now for some reason, you need to completely wipe off your Field catalog in your Inherited class. You have about bunch of columns which you want to reuse the text symbols created in Super class. Since Text symbols are embedded in Super Class, they are not accessible from any other class.

Demo Class Hierarchy

Class ZCL_TEST_NP_SUPER has the logic to build the Field Catalog and it has text symbol T01.

Text Symbol from the Super Class

Solution

I created a small utility class. In this, you specify your current object (as me) when instantiating the object. This utility class has method to get access of the specific text symbol. The object actually collects all the classes in the class hierarchy for which you want to read text symbols. Once collected, it would get the text symbols by using READ

Whenever you need to get an access to the class, you include this object in your class. Call the method _TEXT( ) and you are done.

Class methods & Attributes

This class has these components:

  • Method CONSTRUCTOR – Accept the current object as the object reference. Logic would determine the actual Class name using the RTTS Object descriptor. You use the RTTS to describe the type & Create the type to create dynamic tables are runtime. Once the class name is obtained, it would than look for class’s parent class from where it got inherited using the method GET_ALL_SUPER. It would collect all classes till it reached the point where there is no Super class. Using READ TEXTPOOL, method would determine all the text Symbols used in its Super Class.
  • Method TEXT_ – I wanted to keep the name similar to kind TEXT- so, I used method name as TEXT_. In this method, you read the collected text from the internal table and return back the value.
  • Attribute T_TEXT – This internal table collect the text elements from the text pool of all super classes in class hierarchy.

Code Lines

Code lines for ZCL_TEXT_SYMBOL definition and implementation

Class ZCL_TEXT_SYMBOL

 
*&---------------------------------------------------------------------*
*& Purpose  : Utility to access Text Symbols from Super Class
*& Author   : Naimesh Patel
*& URL      : http://zevolving.com/?p=1769
*&---------------------------------------------------------------------*
CLASS zcl_text_symbol DEFINITION.
  PUBLIC SECTION.
    METHODS:
    constructor
      IMPORTING io_obj TYPE REF TO object,
    text_
      IMPORTING textid TYPE char3
      RETURNING value(rv_val) TYPE string.
  PRIVATE SECTION.
    TYPES:
      BEGIN OF lty_super,
        name TYPE string,
      END   OF lty_super.
    TYPES: tt_super TYPE STANDARD TABLE OF lty_super WITH DEFAULT KEY.
    DATA: t_text    TYPE TABLE OF textpool.
    METHODS:
      get_all_super
        IMPORTING iv_class_name TYPE string
        RETURNING value(rt_super) TYPE tt_super.
ENDCLASS.                    "zcl_text_symbol DEFINITION
*
*
*
CLASS zcl_text_symbol IMPLEMENTATION.
  METHOD constructor.
    DATA: lo_obj_desc   TYPE REF TO cl_abap_objectdescr.
    DATA: lv_class_name TYPE string.
    DATA: lt_super      TYPE tt_super.
    DATA: ls_super      LIKE LINE OF lt_super.
    DATA: lv_class_inc  TYPE char32.
    DATA: lt_text       TYPE TABLE OF textpool.
 
*   get class name
    lo_obj_desc ?= cl_abap_objectdescr=>describe_by_object_ref( io_obj ).
    lv_class_name = lo_obj_desc->get_relative_name( ).
*
*   get all super classes
    lt_super = me->get_all_super( lv_class_name ).
*
* For each supre class, build the class include name and read
* Texts
    LOOP AT lt_super INTO ls_super.
*
      lv_class_inc = ls_super-name.
      lv_class_inc+30(2) = 'CP'.
      TRANSLATE lv_class_inc USING ' ='.
*
      READ TEXTPOOL lv_class_inc INTO lt_text LANGUAGE sy-langu.
      APPEND LINES OF lt_text TO t_text.
    ENDLOOP.
 
    SORT t_text BY id.
 
  ENDMETHOD.                    "constructor
  METHOD text_.
    DATA: ls_text LIKE LINE OF me->t_text.
*   get text of text_id
    READ TABLE me->t_text INTO ls_text
      WITH KEY key = textid
      BINARY SEARCH.
    CHECK sy-subrc EQ 0.
*   send back the value
    rv_val = ls_text-entry.
  ENDMETHOD.                    "_text
*
  METHOD get_all_super.
 
    TYPE-POOLS: seor.
    DATA: lv_super TYPE vseoextend-refclsname.
    DATA: lv_first TYPE flag.
    DATA: ls_key   TYPE seoclskey.
    DATA: ls_inher TYPE seor_inheritance_r.
    DATA: ls_super LIKE LINE OF rt_super.
 
*   when there is class determined
    CHECK iv_class_name IS NOT INITIAL.
 
    lv_first = 'X'.
    ls_key   = iv_class_name.
 
*   till the top node or the first time
    WHILE lv_super IS NOT INITIAL
      OR  lv_first = 'X'.
      CLEAR lv_first.     " no more first time
*     get class inheritance
      CALL FUNCTION 'SEO_INHERITANC_READ'
        EXPORTING
          clskey             = ls_key
        IMPORTING
          inheritance        = ls_inher
        EXCEPTIONS
          class_not_existing = 1
          OTHERS             = 2.
*     exit when error
      IF sy-subrc <> 0.
        EXIT.
      ENDIF.
*     collect the super class in return table
      CLEAR lv_super.
      IF ls_inher-refclsname IS NOT INITIAL.
        ls_super-name = ls_inher-refclsname.
        APPEND ls_super TO rt_super.
        lv_super = ls_inher-refclsname.
*       super is now key
        ls_key = lv_super.
      ELSE.
        EXIT.   " exit when no super class
      ENDIF.
    ENDWHILE.
 
  ENDMETHOD.                    "get_all_super
 
ENDCLASS.                    "zcl_text_symbol IMPLEMENTATION
 

Demo Class

Here is the demo code which uses this utility class to access the text symbol from the Super class:

 
METHOD build_fcat.
* no need to call super
 
  DATA: ct_fcat TYPE lvc_t_fcat.
  FIELD-SYMBOLS: <lfs_fcat> LIKE LINE OF ct_fcat.       " WA for FCAT
*
* Utility to access text symbols
  DATA: lo_text TYPE REF TO zcl_text_symbol.
  CREATE OBJECT lo_text
    EXPORTING
      io_obj = me.
*
  APPEND INITIAL LINE TO ct_fcat ASSIGNING <lfs_fcat>.
  <lfs_fcat>-col_pos   = 5.
  <lfs_fcat>-fieldname = 'ZZWEIGHT'.
  <lfs_fcat>-outputlen = '11'.
  <lfs_fcat>-scrtext_l = lo_text->text_( 'T01' ).   " Accessing Super's T01
  <lfs_fcat>-scrtext_m = lo_text->text_( 'T01' ).
 
 
ENDMETHOD.
 

Talk Back

Let me know what do you think – Text Symbols in Class Pool are Public or Private? Read Poll – Are Text Symbols Private or Public in OO ABAP? for full story.

Are Text Symbols Public or Private?

  • Private - no body can use it (44%, 49 Votes)
  • Public - Every client can use it (43%, 48 Votes)
  • Not Sure - I can't decide (13%, 14 Votes)

Total Voters: 111

Loading ... Loading ...

Do you have any other trick to access the Text Symbols of the Super class within the methods of the inherited class?

Like It? Share!!

Don't miss an Update

Get notified of the new post, right into your inbox

Naimesh Patel{272 articles}

I'm SAP ABAP Consultant for more than a decade. I like to experiment with ABAP especially OO. I have been SDN Top Contributor.
Follow :

Explore all of his 272 articles.

Load comments

9 Comments

  • Steven Oldner

    Ouch, my brain hurts for all this new knowledge. Actually I never thought about this before. Great Blog! Thanks for the mental pain!

  • Hello Steve,

    You would definitely appreciate some mental tricks :)

    Using Text Symbols happens a lot when you leverage ABAP Objects. If you are fan of code inspector and don’t want to use Character strings, you would run into this type of situation where you think, I already have this text mentioned in my super class, why do I need to create it again here?

    Regards,
    Naimesh Patel

  • Kesari

    Hi Naimesh,

    A nice and core technical filling for the ABAP OO Gap :) .

    I was just wondering how can we handle the Duplicate Text IDs..as the same T01 will have different meaning across different classes as part of multi-level inheritance. So I think at this point of time, its Designers responsibility to consciously declare unique text IDs in this approach.

    I was just thinking if we can use an Interface which is implemented by all such sub class hierarchy and we declare the texts as attributes ( the true form of object orientation ) and the default value with text element .

    Thanks.

    Regards
    Kesari Katakam

  • Hello Kesari,

    Regarding the Duplicate Text ID – One option could be have the immediate Super Class as the Priority. Like When you redefine a method, the SUPER->METHOD( ) call would ultimately call the immediate implementation of that method.

    You can have another column in your internal table to save the Super Class name. You also need to save your inheritance tree as well. In the TEXT_ method, you need to search the text ID in each Class’s text ID pool. Once you find it you can exit out.

    Regarding the Interface Usage – I’m not sure about that approach. There are no text IDs for Interface as well as I don’t think we can translate constants. The basic purpose of using text symbols is to be able to extend the program in different languages.

    Regards,
    Naimesh Patel

  • Ramesh

    Here is a possible alternative illustrated using three classes Y1, Y2 (inheriting from Y1) & Y3 (inheriting from Y2) and a test program.

     
    *=============================================
    class y1:
     
     
    methods text_from_pool
        importing
          !iv_txtid type inum
        returning
          value(ev_text) type string .
     
    method text_from_pool.
      data:
        lv_var type string.
      field-symbols:
        &lt;txt&gt; type any.
      concatenate 'TEXT-' iv_txtid into lv_var.
      assign (lv_var) to <txt>;.
      if sy-subrc = 0.
        ev_text = <txt>;.
      endif.
    endmethod.
     
     
    Text pool:
    T01	Class Y1: TEXT-T01
    T02	Class Y1: TEXT-T02
    T03	Class Y1: TEXT-T03
     
    =============================================
    class y2  inheriting from y1:
     
     
    method text_from_pool. "redefinition
      data:
        lv_var type string.
      field-symbols:
        &lt;txt&gt; type any.
      concatenate 'TEXT-' iv_txtid into lv_var.
      assign (lv_var) to <txt>.
      if sy-subrc = 0.
        ev_text = <txt>.
      else.
        ev_text = super->text_from_pool( iv_txtid ).
      endif.
    endmethod.
     
     
    Text pool:
    T02	Class Y2: TEXT-T02
    T03	Class Y2: TEXT-T03
     
    =================================================================
     
    class y3 inheriting from y2:
     
     
    method text_from_pool. "redefinition
      data:
        lv_var type string.
      field-symbols:
        &lt;txt&gt; type any.
      concatenate 'TEXT-' iv_txtid into lv_var.
      assign (lv_var) to <txt>.
      if sy-subrc = 0.
        ev_text = <txt>.
      else.
        ev_text = super->text_from_pool( iv_txtid ).
      endif.
    endmethod.
     
     
    Text pool:
    T03	Class Y3: TEXT-T03
     

    =========================================================
    Test program:

     
    REPORT  ztest.
     
    data:
      obj TYPE REF TO y3,
      str type string.
     
    CREATE OBJECT obj.
    str = obj->TEXT_FROM_POOL( 'T01' ). write:/ str.
    str = obj->TEXT_FROM_POOL( 'T02' ). write:/ str.
    str = obj->TEXT_FROM_POOL( 'T03' ). write:/ str.
     

    =====================================================
    Result:

    Class Y1: TEXT-T01
    Class Y2: TEXT-T02
    Class Y3: TEXT-T03

  • Hello Ramesh,

    Thanks for your example and class hierarchy.

    In this approach, I have to have the method TEXT_FROM_POOL in my class hierarchy and it has to have an implementation to get the TEXT ID. I don’t want to have the class in hierarchy as I would definitely like to re use this in my other classes. If the method is buried in the class hierarchy, it would defeat the update of re-usability.

    If you want to have the TEXT ID from specific class preference, you need to have similar structure as I discussed in my reply to Kesari.

    Let me know if I have misunderstood the purpose of your example.

    Regards,
    Naimesh Patel

  • Ramesh

    I understand your solution is implemented using a stand alone utility class which can run against any hierarchy.

    I have provided an alternative where you can transparently access text from the closest ancestor for a given text id. To use it as a repository from outside the class hierarchy you can just tap into a class at the needed level and call its TEXT_FROM_POOL method. In the latter case it indeed suffers from the requirement of defining the method in each of the class.

    I have used it in a project for giving the inheriting class flexibility of using the (general) text from the ancestors. if I feel I need to be more specific then I redefine it in the inheriting class.

    Thanks for sharing ths solution and keep up the good work Naimesh!

  • Hello Ramesh,

    Thanks for clarifying the purpose.

    I guess we can extend the utility class to also pass optional parameter as the class name and get the desired Text ID. I would try to compile another post with that example.

    Regards,
    Naimesh Patel

  • Ramesh

    Hi Naimesh,

    Sounds good!

    Basically 2 approaches to the requirement. The requirement being to have the ability to inherit/redefine texts (like other components). With the utility class you instantiate it with the caller’s class to achieve this.

    Sorry for deviating form your original (general) objective (ability to read texts from any class hierarchy).

    Regards,
    Ramesh

Comments on this Post are now closed. If you have something important to share, you can always contact me.

You seem to be new here. Subscribe to stay connected.