Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Inherited static method to return instance of sub-class

Former Member
0 Kudos

Hi,

I am working with NetWeaver 7.01.

Since ABAP Objects does not allow multiple constructors, I have defined a static method CREATE_FROM_SY_MSG_VARIABLES on a parent exception class, let's call it ZCX_GENERAL_FAULT, that creates an instance of the exception class where the textid is built from the system message variables.

METHOD create_from_sy_msg_variables.

  DATA:
     ls_textid TYPE scx_t100key.

* Build the text ID from the system message variables...
  ...

* Return the exception back via returning parameter RESULT
  CREATE OBJECT result
    EXPORTING
      textid = ls_textid.

ENDMETHOD.

I would like to then have this general exception sub-classed to get more specific exceptions thrown in the application logic. In the following example, both exception classes ZCX_INVALID_FORMAT and ZCX_MISSING_DATA are sub-classes of ZCX_GENERAL_FAULT.

  DATA:
    lo_exception TYPE REF TO zcx_general_fault.

  CALL FUNCTION '...'
    EXPORTING
      ...
    EXCEPTIONS
      invalid_format = 1
      missing_data  = 2.

  CASE sy-subrc.
    WHEN 1.  lo_exception = zcx_invalid_format=>create_from_sy_msg_variables( ).
    WHEN 2.  lo_exception = zcx_missing_data=>create_from_sy_msg_variables( ).
  ENDCASE.

  IF lo_exception IS BOUND.
    RAISE EXCEPTION lo_exception.
  ENDIF.

The problem with this approach is of course that method CREATE_FROM_SY_MSG_VARIABLES is creating an instance of ZCX_GENERAL_FAULT, not one of the sub-classes, whereas what I really want are instances of the sub-classes.

Does anyone know of a way to do this with ABAP Objects? The only approach I can think of, given that static methods cannot be re-defined nor can exception constructors be changed, is to pass the desired exception class name through - which is just awful.

METHOD create_from_sy_msg_variables.

  ...

  CREATE OBJECT result TYPE (x_exception_class)
    EXPORTING
      textid = ls_textid.

ENDMETHOD.

lo_exception = zcx_invalid_format=>create_from_sy_msg_variables( 'ZCX_INVALID_FORMAT' ).

Incidentally, it would be so much nicer if ABAP let classes (not just instances of classes) be passed around as data types so that we didn't have to pass them as text strings...

Kind regards,

Scott

1 ACCEPTED SOLUTION

Former Member
0 Kudos

Hello,

I have also had this problem when using inheritance together with the singleton pattern in ABAP Object. It is really a pity that ABAP Objects does not allow to redefine static methods. Anyway, I finally found a hack to solve the problem:

1. Change the signature of the static factory method (create_from_sy_msg_variables), so that the method does not have a RETURNING parameter, but a CHANGING parameter of type ANY.

2. Inside the factory method, use RTTI to determine the actual object type the given parameter points to.

3. Create an object of this class dynamically within the factory method.

4. If the class constructor of the superclass is private, the subclass needs to be a friend of the superclass (is necessary for object creation of the subclass within the factory method of the superclass).

(see sample in the next post)

Edited by: David Klotz on Jul 8, 2009 9:45 PM

4 REPLIES 4

naimesh_patel
Active Contributor
0 Kudos

There is no way unless you explicitly tell the CREATE object statement to instantiate the object for Sub-Class.

For you design, try like this:

1) Make sure you have the Attribute TEXTID in ZCX_GENERAL_FAULT. If you have inherited this class from generic exception class CX_STATIC_CHECK than TEXTID would be available in your class.

2) Change the implementation of the CREATE_FROM_SY_MSG_VARIABLES method. Save the derived TEXTID in the attribute TEXTID.


METHOD create_from_sy_msg_variables.
  DATA:  ls_textid TYPE scx_t100key.

* Build the text ID from the system message variables...
  ...
* save to attribute 
  me->textid = ls_textid.
ENDMETHOD.

3) Call method CREATE_FROM_SY_MSG_VARIABLES in CONSTRUCTOR of super class ZCX_GENERAL_FAULT.


method CONSTRUCTOR.
CALL METHOD SUPER->CONSTRUCTOR
EXPORTING
TEXTID = TEXTID
PREVIOUS = PREVIOUS

CREATE_FROM_SY_MSG_VARIABLES( ).

endmethod.

4) Constructors of the Sub-classes must call the constructor of the Super Class.

5) change the raise exception


  CASE sy-subrc.
    WHEN 1.  
      raise exception type zcx_invalid_format .
    WHEN 2. 
      raise exception type zcx_missing_data.
  ENDCASE.

Regards,

Naimesh Patel

Former Member
0 Kudos

Hi Naimesh,

Thanks for taking the time to respond. Unfortunately, the suggestion doesn't work because it is not possible to change the constructor of an exception class...

Kind regards,

Scott

Former Member
0 Kudos

Hello,

I have also had this problem when using inheritance together with the singleton pattern in ABAP Object. It is really a pity that ABAP Objects does not allow to redefine static methods. Anyway, I finally found a hack to solve the problem:

1. Change the signature of the static factory method (create_from_sy_msg_variables), so that the method does not have a RETURNING parameter, but a CHANGING parameter of type ANY.

2. Inside the factory method, use RTTI to determine the actual object type the given parameter points to.

3. Create an object of this class dynamically within the factory method.

4. If the class constructor of the superclass is private, the subclass needs to be a friend of the superclass (is necessary for object creation of the subclass within the factory method of the superclass).

(see sample in the next post)

Edited by: David Klotz on Jul 8, 2009 9:45 PM

0 Kudos

Here is a sample:

Definition and implementation of the superclass (including the factory method)


CLASS lcl_super DEFINITION CREATE PRIVATE.
  PUBLIC SECTION.
    CLASS-METHODS create_object
      CHANGING co_obj TYPE any.
ENDCLASS.

CLASS lcl_super IMPLEMENTATION.
  METHOD create_object.                " <-- the factory method

    DATA:
      lo_type_descr_obj  TYPE REF TO cl_abap_typedescr,
      lo_ref_descr       TYPE REF TO cl_abap_refdescr,
      lo_type_descr_ref  TYPE REF TO cl_abap_typedescr,
      le_typename        TYPE abap_abstypename.

*   Get the type name of the referred object
    lo_type_descr_obj = cl_abap_refdescr=>describe_by_data( co_obj ).
    IF NOT lo_type_descr_obj->kind = cl_abap_typedescr=>kind_ref.
*     Param is not an object reference -> Raise an exception
*     RAISE ...
    ELSE.
      lo_ref_descr ?= lo_type_descr_obj.
      lo_type_descr_ref = lo_ref_descr->get_referenced_type( ).
      le_typename = lo_type_descr_ref->absolute_name .

*     Create an object of this type into the given reference variable
      TRY.
          CREATE OBJECT co_obj TYPE (le_typename).
        CATCH cx_sy_create_object_error.
*         Exception handling...
      ENDTRY.
    ENDIF.
  ENDMETHOD.
ENDCLASS.

A subclass which extends LCL_SUPER (note that this class must be a friend of LCL_SUPER, because the superclass only allows private object creation):


CLASS lcl_sub DEFINITION INHERITING FROM lcl_super FRIENDS lcl_super.
  PUBLIC SECTION.
    METHODS do_foo.
ENDCLASS.

CLASS lcl_sub IMPLEMENTATION.
  METHOD do_foo.
    WRITE / 'Foo'.
  ENDMETHOD.
ENDCLASS.

Finally, the simple usage:


DATA: go_sub TYPE REF TO lcl_sub.

* Use the static factory method of the superclass to receive an
* instance of the children class
lcl_super=>create_object( CHANGING co_obj = go_sub ).

* Use a method of the subclass
go_sub->do_foo( ).               "writes 'Foo'

Hope this helps,

David