Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
Former Member

Like many other garbage-collected programming language, ABAP has its own version of weak references . They are implemented using the class REPORT z_test_weak_ref_buffer.

----


TYPES: t_status_id TYPE c LENGTH 10.

----


  •       CLASS lcl_my_status DEFINITION

----


CLASS lcl_my_status DEFINITION.

  PUBLIC SECTION.

    DATA status_id TYPE t_status_id.

ENDCLASS.                    "lcl_my_status DEFINITION

----


TYPES: BEGIN OF t_status_map_entry,

         id TYPE t_status_id,

         instance TYPE REF TO lcl_my_status,

       END OF t_status_map_entry,

       tt_status_map TYPE HASHED TABLE OF t_status_map_entry WITH UNIQUE KEY id.

----


  •       CLASS lcl_my_buffer DEFINITION

----


CLASS lcl_my_buffer DEFINITION CREATE PRIVATE.

  PUBLIC SECTION.

    CLASS-METHODS get_instance

      RETURNING value(rr_instance) TYPE REF TO lcl_my_buffer.

    METHODS constructor.

    METHODS get_status

      IMPORTING i_status_id TYPE t_status_id

      RETURNING value(rr_status) TYPE REF TO lcl_my_status.

  PRIVATE SECTION.

    CLASS-DATA sr_instance TYPE REF TO cl_abap_weak_reference.

    DATA gt_status_map TYPE tt_status_map.

ENDCLASS.                    "lcl_my_buffer DEFINITION

----


  •       CLASS lcl_my_buffer IMPLEMENTATION

----


CLASS lcl_my_buffer IMPLEMENTATION.

  METHOD get_instance.

    IF sr_instance IS INITIAL.

  •     method called for the very first time

      CREATE OBJECT rr_instance.

      CREATE OBJECT sr_instance

        EXPORTING

          oref = rr_instance.

    ELSE.

  •     try to get the buffered instance using the weak reference

      rr_instance ?= sr_instance->get( ).

      IF rr_instance IS INITIAL.

  •       the instance was garbage-collected, re-create it

        CREATE OBJECT rr_instance.

        CREATE OBJECT sr_instance

          EXPORTING

            oref = rr_instance.

      ENDIF.

    ENDIF.

  ENDMETHOD.                    "get_instance

  METHOD constructor.

    DATA: ls_entry TYPE t_status_map_entry.

  •   populate the buffer with some entries

    CREATE OBJECT ls_entry-instance.

    ls_entry-instance->status_id = 'FOO'.

    ls_entry-id = ls_entry-instance->status_id.

    INSERT ls_entry INTO TABLE gt_status_map.

    CREATE OBJECT ls_entry-instance.

    ls_entry-instance->status_id = 'BAR'.

    ls_entry-id = ls_entry-instance->status_id.

    INSERT ls_entry INTO TABLE gt_status_map.

  ENDMETHOD.                    "constructor

  METHOD get_status.

    FIELD-SYMBOLS:  TYPE t_status_map_entry.

    READ TABLE gt_status_map ASSIGNING  WITH TABLE KEY id = i_status_id.

    rr_status = -instance.

  ENDMETHOD.                    "get_status

ENDCLASS.                    "lcl_my_buffer IMPLEMENTATION

DATA: gr_buffer TYPE REF TO lcl_my_buffer,

      gr_status_foo_1 TYPE REF TO lcl_my_status,

      gr_status_foo_2 TYPE REF TO lcl_my_status.

START-OF-SELECTION.

  gr_buffer = lcl_my_buffer=>get_instance( ).

  gr_status_foo_1 = gr_buffer->get_status( 'FOO' ).

  WRITE: / 'Got a status: ', gr_status_foo_1->status_id.

  CLEAR gr_buffer.

  CALL FUNCTION 'POPUP_TO_CONFIRM'

    EXPORTING

      text_question = 'Have you tried Control-Alt-Delete?'.

  gr_buffer = lcl_my_buffer=>get_instance( ).

  gr_status_foo_2 = gr_buffer->get_status( 'FOO' ).

  WRITE: / 'Still got the first status: ', gr_status_foo_1->status_id.

  WRITE: / 'Got another status: ', gr_status_foo_2->status_id.

  IF gr_status_foo_1 = gr_status_foo_2.

    WRITE: / 'gr_status_foo_1 = gr_status_foo_2 - fine so far.'.

  ELSE.

    WRITE: / 'gr_status_foo_1 <> gr_status_foo_2 - malicious developer deception happening right now'.
ENDIF.

You might already have guessed the results:

Got a status: FOO
Still got the first status: FOO
Got another status: FOO
gr_status_foo_1 <> gr_status_foo_2 - malicious developer deception happening right now

In this case, the singleton buffer object was garbage-collected, but the status objects that were supposed to be managed by this singleton were not. The re-created buffer object then provided its own set of status objects - and suddenly, we have different object instances representing the same logical object.

To avoid this kind of situation, there's a simple rule of thumb: A managed object should know its manager. Just make sure that every status object keeps a static reference to the buffer that created it - this will prevent the garbage collection of the buffer as long as one of the status objects is still alive. And always keep in mind that the ABAP garbage collector is rather agressive compared to other programming environments.

1 Comment