This is a test message to test the length of the message box.
Login
ABAP Type casting
Created by Software-Heroes

ABAP - Type Casting

556

How do you actually get the original type of a class or instance if it is passed in a generic table? In this article we examine the possibilities.



When passing a generic table with many instances, in some situations you may also want to obtain further information from the object. In such cases you have to perform a CAST to change the type and thus the access options.

 

Introduction

In object-oriented development, you often work with objects that inherit from an interface, but then also contain specific information. Such objects are usually managed in tables of "unspecific" type so that all types of objects can be stored and so that a separate table is not needed for each object. In this example we will look at the new application log and try to access the various contents of the messages.

 

Preparation

In the first step we create a log, using the example from the article for the new application log to create a message handle. We can now read this to get the news.

DATA(lt_messages) = cl_bali_log_db=>get_instance( )->load_log( c_handle )->get_all_items( ).

 

After reading the messages, we get the LT_MESSAGES table with different references to different objects:

 

Find Interface

Before we can start processing, we should find the right interface. Once we have an object, we don't need to recreate it in the appropriate type, we just need to cast it to the appropriate type. In most cases we use the interface for this, as it is the public representation of the class to the outside world, with all the methods and attributes we can use. Let’s take a closer look at the class CL_BALI_MESSAGE_GETTER:

 

The class has two interfaces, which provide various attributes and methods. In the class, however, the entirety of both interfaces is available to us. The interface IF_BALI_ITEM_GETTER seems to be the generic interface as it provides general information about the log item, such as SEVERITY, TIMESTAMP or the GET_MESSAGE_TEXT method.

 

If we now look at the interface IF_BALI_MESSAGE_GETTER, we will see specific attributes that describe a T100 message, such as the message variables or the message ID.

 

This means that for the following processing, we need the specific interfaces to get the dependent information of the messages and not just the "text".

 

Variant 0 - Classic

The classic variant comes in different versions, you could try to get the information about the type via the type description (RTTI) or you could try a CAST on the corresponding type. In this example we first try a simple CAST, but do not use the old variant "?=" of the assignment.

DATA(lo_message) = CAST if_bali_message_getter( ls_message-item ).
io_out->write( lo_message->id ).
io_out->write( lo_message->number ).
io_out->write( lo_message->variable_1 ).
io_out->write( lo_message->get_message_text( ) ).

 

Since we are working with several types here, it can also happen that the cast does not work. If this is the case, an exception of type CX_SY_MOVE_CAST_ERROR is generated. We should catch this exception and use TRY/CATCH to do this.

TRY.
    DATA(lo_message) = CAST if_bali_message_getter( ls_message-item ).
    io_out->write( lo_message->id ).
    io_out->write( lo_message->number ).
    io_out->write( lo_message->variable_1 ).
    io_out->write( lo_message->get_message_text( ) ).

  CATCH cx_sy_move_cast_error.
ENDTRY.

 

If this worked, we can end the loop with CONTINUE, as another cast makes no sense. We repeat this accordingly for the other types in order to obtain the specific information. The final loop could look like this:

LOOP AT it_messages INTO DATA(ls_message).
  TRY.
      DATA(lo_message) = CAST if_bali_message_getter( ls_message-item ).
      io_out->write( lo_message->id ).
      io_out->write( lo_message->number ).
      io_out->write( lo_message->variable_1 ).
      io_out->write( lo_message->get_message_text( ) ).

      CONTINUE.

    CATCH cx_sy_move_cast_error.
  ENDTRY.

  TRY.
      DATA(lo_free_text) = CAST if_bali_free_text_getter( ls_message-item ).
      io_out->write( lo_free_text->get_message_text( ) ).

      CONTINUE.

    CATCH cx_sy_move_cast_error.
  ENDTRY.

  TRY.
      DATA(lo_exception) = CAST if_bali_exception_getter( ls_message-item ).
      io_out->write( lo_exception->exception_class ).
      io_out->write( lo_exception->exception_id_name ).
      io_out->write( lo_exception->get_message_text( ) ).

      CONTINUE.

    CATCH cx_sy_move_cast_error.
  ENDTRY.
ENDLOOP.

 

Variant 1 - IS INSTANCE

The variant with IS INSTANCE offers a slightly simpler way and without exception handling. We can use an IF statement to query whether the object can be assigned to a corresponding class or interface. If this is the case, we can carry out a cast.

IF ls_message-item IS INSTANCE OF if_bali_message_getter.
  DATA(lo_message) = CAST if_bali_message_getter( ls_message-item ).
  io_out->write( lo_message->id ).
  io_out->write( lo_message->number ).
  io_out->write( lo_message->variable_1 ).
  io_out->write( lo_message->get_message_text( ) ).
ENDIF.

 

We can chain the queries and thus save error handling and continuing, the processing looks much tidier at the end:

LOOP AT it_messages INTO DATA(ls_message).
  io_out->write( `-` ).

  IF ls_message-item IS INSTANCE OF if_bali_message_getter.
    DATA(lo_message) = CAST if_bali_message_getter( ls_message-item ).
    io_out->write( lo_message->id ).
    io_out->write( lo_message->number ).
    io_out->write( lo_message->variable_1 ).
    io_out->write( lo_message->get_message_text( ) ).

  ELSEIF ls_message-item IS INSTANCE OF if_bali_free_text_getter.
    DATA(lo_free_text) = CAST if_bali_free_text_getter( ls_message-item ).
    io_out->write( lo_free_text->get_message_text( ) ).

  ELSEIF ls_message-item IS INSTANCE OF if_bali_exception_getter.
    DATA(lo_exception) = CAST if_bali_exception_getter( ls_message-item ).
    io_out->write( lo_exception->exception_class ).
    io_out->write( lo_exception->exception_id_name ).
    io_out->write( lo_exception->get_message_text( ) ).

  ENDIF.

ENDLOOP.

 

Variant 2 - CASE TYPE

In the last example, the simplest variant so far, as it is easy to overview and saves unnecessary code. We use the CASE TYP statement. This statement is an extension of the classic CASE and can also create types. In WHEN we query the corresponding interface and assign it to a specific variable.

CASE TYPE OF ls_message-item.
  WHEN TYPE if_bali_message_getter INTO DATA(lo_message).
    io_out->write( lo_message->id ).
    io_out->write( lo_message->number ).
    io_out->write( lo_message->variable_1 ).
    io_out->write( lo_message->get_message_text( ) ).

ENDCASE.

 

Now we call the conversion in the loop and get the same result as with the other variants. This variant is even shorter and a little clearer. You will no longer find a CAST either, as this is taken over by the CASE TYPE.

LOOP AT it_messages INTO DATA(ls_message).
  io_out->write( `-` ).

  CASE TYPE OF ls_message-item.
    WHEN TYPE if_bali_message_getter INTO DATA(lo_message).
      io_out->write( lo_message->id ).
      io_out->write( lo_message->number ).
      io_out->write( lo_message->variable_1 ).
      io_out->write( lo_message->get_message_text( ) ).

    WHEN TYPE if_bali_free_text_getter INTO DATA(lo_free_text).
      io_out->write( lo_free_text->get_message_text( ) ).

    WHEN TYPE if_bali_exception_getter INTO DATA(lo_exception).
      io_out->write( lo_exception->exception_class ).
      io_out->write( lo_exception->exception_id_name ).
      io_out->write( lo_exception->get_message_text( ) ).

  ENDCASE.
ENDLOOP.

 

Full example

Here is the complete class from the various examples. You will probably have to adjust the handle object if you want to run it on your system, as your system has its own ID created.

CLASS zcl_bs_demo_type_casting DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

  PRIVATE SECTION.
    CONSTANTS c_handle TYPE if_bali_log_db=>ty_handle VALUE '<YOUR_HANDLE>'.

    METHODS classic_casting
      IMPORTING it_messages TYPE if_bali_log=>ty_item_table
                io_out      TYPE REF TO if_oo_adt_classrun_out.

    METHODS if_casting
      IMPORTING it_messages TYPE if_bali_log=>ty_item_table
                io_out      TYPE REF TO if_oo_adt_classrun_out.

    METHODS case_casting
      IMPORTING it_messages TYPE if_bali_log=>ty_item_table
                io_out      TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.


CLASS zcl_bs_demo_type_casting IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    DATA(lt_messages) = cl_bali_log_db=>get_instance( )->load_log( c_handle )->get_all_items( ).

    out->write( `--> CLASSIC` ).
    classic_casting( it_messages = lt_messages
                     io_out      = out ).

    out->write( |-| ).
    out->write( `--> IS INSTANCE` ).
    if_casting( it_messages = lt_messages
                io_out      = out ).

    out->write( |-| ).
    out->write( `--> CASE TYPE` ).
    case_casting( it_messages = lt_messages
                  io_out      = out ).
  ENDMETHOD.


  METHOD classic_casting.
    LOOP AT it_messages INTO DATA(ls_message).
      io_out->write( `-` ).

      TRY.
          DATA(lo_message) = CAST if_bali_message_getter( ls_message-item ).
          io_out->write( lo_message->id ).
          io_out->write( lo_message->number ).
          io_out->write( lo_message->variable_1 ).
          io_out->write( lo_message->get_message_text( ) ).

          CONTINUE.

        CATCH cx_sy_move_cast_error.
      ENDTRY.

      TRY.
          DATA(lo_free_text) = CAST if_bali_free_text_getter( ls_message-item ).
          io_out->write( lo_free_text->get_message_text( ) ).

          CONTINUE.

        CATCH cx_sy_move_cast_error.
      ENDTRY.

      TRY.
          DATA(lo_exception) = CAST if_bali_exception_getter( ls_message-item ).
          io_out->write( lo_exception->exception_class ).
          io_out->write( lo_exception->exception_id_name ).
          io_out->write( lo_exception->get_message_text( ) ).

          CONTINUE.

        CATCH cx_sy_move_cast_error.
      ENDTRY.
    ENDLOOP.
  ENDMETHOD.


  METHOD if_casting.
    LOOP AT it_messages INTO DATA(ls_message).
      io_out->write( `-` ).

      IF ls_message-item IS INSTANCE OF if_bali_message_getter.
        DATA(lo_message) = CAST if_bali_message_getter( ls_message-item ).
        io_out->write( lo_message->id ).
        io_out->write( lo_message->number ).
        io_out->write( lo_message->variable_1 ).
        io_out->write( lo_message->get_message_text( ) ).

      ELSEIF ls_message-item IS INSTANCE OF if_bali_free_text_getter.
        DATA(lo_free_text) = CAST if_bali_free_text_getter( ls_message-item ).
        io_out->write( lo_free_text->get_message_text( ) ).

      ELSEIF ls_message-item IS INSTANCE OF if_bali_exception_getter.
        DATA(lo_exception) = CAST if_bali_exception_getter( ls_message-item ).
        io_out->write( lo_exception->exception_class ).
        io_out->write( lo_exception->exception_id_name ).
        io_out->write( lo_exception->get_message_text( ) ).

      ENDIF.

    ENDLOOP.
  ENDMETHOD.


  METHOD case_casting.
    LOOP AT it_messages INTO DATA(ls_message).
      io_out->write( `-` ).

      CASE TYPE OF ls_message-item.
        WHEN TYPE if_bali_message_getter INTO DATA(lo_message).
          io_out->write( lo_message->id ).
          io_out->write( lo_message->number ).
          io_out->write( lo_message->variable_1 ).
          io_out->write( lo_message->get_message_text( ) ).

        WHEN TYPE if_bali_free_text_getter INTO DATA(lo_free_text).
          io_out->write( lo_free_text->get_message_text( ) ).

        WHEN TYPE if_bali_exception_getter INTO DATA(lo_exception).
          io_out->write( lo_exception->exception_class ).
          io_out->write( lo_exception->exception_id_name ).
          io_out->write( lo_exception->get_message_text( ) ).

      ENDCASE.
    ENDLOOP.
  ENDMETHOD.
ENDCLASS.

 

Availability

From which release are the new statements available? You can find the relevant information in the ABAP Feature Matrix (AFM):

  • IS INSTANCE OF - S/4 HANA 1511 (7.50)
  • CASE TYPE OF - S/4 HANA 1511 (7.50)

 

Conclusion

In the object-oriented ABAP world, casting objects is standard in order to obtain the necessary information in processing and to manage objects generically in your table. We hope that with the help of this article you can now master this better.


Included topics:
New ABAPCASTType Casting
Comments (0)



And further ...

Are you satisfied with the content of the article? We post new content in the ABAP area every Friday and irregularly in all other areas. Take a look at our tools and apps, we provide them free of charge.


ABAP - RETURN value

Category - ABAP

After all these years, the “real” return in ABAP has finally arrived. In this article we will show you how it works and what it can do.

02/13/2024

ABAP Deep Dive - FOR (Loops)

Category - ABAP

Let's take a closer look at the FOR loop. How does it work? What do I have to consider and what can I do with it?

04/14/2023

ABAP Deep Dive - Table access (internal)

Category - ABAP

In this article, let's take a look at table access to internal tables and how they replace READ TABLE.

02/03/2023

ABAP Developer still relevant

Category - ABAP

In this article we look at whether ChatGPT can already replace an ABAP developer or whether it can be used as a help in everyday life.

01/06/2023

ABAP - FINAL

Category - ABAP

In this article, we'll take a look at the new FINAL language construct, how it works, and what you can do with it.

12/23/2022