06-24-2013 11:09 AM
Hello ABAP pros,
I'm trying to dynamically access attributes from within a superclass method. This works for all superclass attributes but not for the subclass attributes.
Imaging the following:
In an abstract superclass I define protected attributes a and b. In a subclass, inheriting from this superclass, I define a third protected attribute c. Now I'd like to define a method in the superclass which should dynamicall fill a structure out of all accessible instance attributes.
This method somehow looks like this:
METHOD to_structure.
DATA:
lref_structure_description TYPE REF TO cl_abap_structdescr,
lref_structure_object TYPE REF TO data,
lv_empty TYPE string.
FIELD-SYMBOLS:
<ls_component> TYPE abap_compdescr,
<lv_value> TYPE any,
<ls_structure> TYPE any,
<lv_structure_component_value> TYPE any.
" get_structure_description( ) is a self written method that returns a RTTI description object of the desired structure of attributes
lref_structure_description = me->get_structure_description( ).
IF es_structure IS REQUESTED.
CREATE DATA lref_structure_object TYPE HANDLE lref_structure_description.
ASSIGN lref_structure_object->* TO <ls_structure>.
LOOP AT lref_structure_description->components ASSIGNING <ls_component>.
IF <lv_value> IS ASSIGNED.
UNASSIGN <lv_value>.
ENDIF.
ASSIGN me->(<ls_component>-name) TO <lv_value>.
IF <lv_value> IS NOT ASSIGNED.
ASSIGN lv_empty TO <lv_value>.
ENDIF.
IF <lv_structure_component_value> IS ASSIGNED.
UNASSIGN <lv_structure_component_value>.
ENDIF.
ASSIGN COMPONENT <ls_component>-name OF STRUCTURE <ls_structure> TO <lv_structure_component_value>.
IF <lv_structure_component_value> IS ASSIGNED.
<lv_structure_component_value> = <lv_value>.
ENDIF.
ENDLOOP.
es_structure = <ls_structure>.
ENDIF.
ENDMETHOD.
The problem lies within the line "ASSIGN me->(<ls_component>-name) TO <lv_value>.". This works for <ls_component>-name = a and <ls_component>-name = b but not for <ls_component>-name = c (the subclass attribute).
I call the method on an instance of the subclass. The debugger shows that "me" is an instance of the subclass and if I enter "me->c" in the debugger I see the corresponding value. But <lv_value> just won't get assigned in this case. It also does not work if I specify the component name fully dynamic (test = 'me->' && <ls_component>-name. ASSIGN (test) TO <lv_value>.) nor if I explicitly use an object reference of the subclass (lref_subclass ?= me. ASSIGN lref_subclass->(<ls_component>-name) TO <lv_value>.).
It's a 7.31 SP3 system.
Any ideas what may be wrong here or is this just not possible?
06-24-2013 2:48 PM
Hi,
I can see where you are coming from. One would assume if value is being displayed in debug window then it can be assigned. Can't really explain what is wrong here but thing which I noticed is changing visibility of attribute C in subclass from protected to public all of sudden make it accessible though ASSIGN statement.
Regards,
Pawan.
06-24-2013 1:45 PM
Hi Christopher,
in my understanding of OO attributes and methods of subclasses are never visible in the superclass method.
06-24-2013 4:11 PM
Hi Uwe,
that is what I was wondering about. If it wasn't possible, it would render dynamic programming quite useless in an OO context as you would have to redefine every method of the superclass that aims to work on subclass attributes.
Regards
Christopher
06-24-2013 2:48 PM
Hi,
I can see where you are coming from. One would assume if value is being displayed in debug window then it can be assigned. Can't really explain what is wrong here but thing which I noticed is changing visibility of attribute C in subclass from protected to public all of sudden make it accessible though ASSIGN statement.
Regards,
Pawan.
06-24-2013 3:37 PM
Hi Pawan,
the visibility really seems to be the problem. I thought, if I call the method of the superclass on an object of the subclass, the visibility wouldn't matter. When I change the visibility of the subclass attribute to "public" or add the superclass as a friend to the subclass definition it works seamlessly. Thank you for the pointer!
I used the following two classes to test this:
class Z_CL_TEST_SUPER definition
public
abstract
create public .
public section.
methods CONSTRUCTOR
importing
!IV_A type STRING
!IV_B type STRING .
methods GET_C
returning
value(RV_VALUE) type STRING .
protected section.
data ATTR_SUP_A type STRING .
data ATTR_SUP_B type STRING .
private section.
ENDCLASS.
CLASS Z_CL_TEST_SUPER IMPLEMENTATION.
METHOD constructor.
me->attr_sup_a = iv_a.
me->attr_sup_b = iv_b.
ENDMETHOD.
METHOD get_c.
DATA:
lref_subclass TYPE REF TO z_cl_test_sub,
lv_attribute_name TYPE string.
FIELD-SYMBOLS:
<lv_attribute_value> TYPE string.
lv_attribute_name = 'attr_sub_c'.
TRY.
lref_subclass ?= me.
ASSIGN me->(lv_attribute_name) TO <lv_attribute_value>.
IF <lv_attribute_value> IS ASSIGNED.
rv_value = <lv_attribute_value>.
ENDIF.
CATCH cx_root.
ENDTRY.
ENDMETHOD.
ENDCLASS.
class Z_CL_TEST_SUB definition
public
inheriting from Z_CL_TEST_SUPER
create public
global friends Z_CL_TEST_SUPER .
public section.
methods CONSTRUCTOR
importing
!IV_A type STRING
!IV_B type STRING
!IV_C type STRING .
protected section.
data ATTR_SUB_C type STRING .
private section.
ENDCLASS.
CLASS Z_CL_TEST_SUB IMPLEMENTATION.
METHOD constructor.
super->constructor(
iv_a = iv_a
iv_b = iv_b
).
me->attr_sub_c = iv_c.
ENDMETHOD.
ENDCLASS.
DATA:
lref_subclass TYPE REF TO z_cl_test_sub,
lv_c TYPE string.
CREATE OBJECT lref_subclass
EXPORTING
iv_a = 'A'
iv_b = 'B'
iv_c = 'C'.
lv_c = lref_subclass->get_c( ).
When removing the friends statement, get_c won't return the value anymore.
Regards
Christopher
Message was edited by: Christopher Fenn
06-24-2013 3:12 PM
Hi Christopher,
The Subclass attributes cannot be accessed in the Super class, why because the Subclass attributes are not visible to Super Class.
-Thanks,
Vijay
02-16-2016 10:05 AM
If this is on purpose by SAP, this is kinda ridiculous. The super class is becoming part of the sub class, and the methods should behave exactly the same, with the same code.
This should work in either context, because me is of the same type, and should have the same visibility, no matter where it was declared:
ASSIGN me->(attr_name) TO <data>.
From my perspective this clearly is a bug in ABAP. But as always SAP is probably going to ignore this, or simply say it is on purpose, because [fill in excuse of the day].
06-24-2013 3:47 PM
I think you'll just have to override the superclass method in your subclass to do what you need it to do... You can still call the superclass method and add some extra logic after.
I also believe that a superclass having any knowledge of its subclasses is not really proper use of inheritance.
06-25-2013 8:00 AM
Hello Lucas,
redefining the superclass method, implementing the subclass specific code in it and calling the superclass method afterwards, sounds like a great idea. Thank you for the hint!
My goal was to make the "framework" easily extensible by adding new subclasses to it. So I focused on implementing as much as possible in the abstract superclass (like persistency, serialisation, ...). The superclass methods are very generic through heavy usage of RTTI / RTTC classes. They have no special knowledge of the subclasses using it. The subclasses, on the other hand, have to follow some naming / visibility conventions to work as desired. The sample code I posted is greatly simplified to illustrate the problem I had.
Regards
Christopher
03-05-2015 2:51 PM
Hi,
I just stumbled upon this poroblem as well. ABAP Keyword Documentation states that this "may be used for all visible attributes of objects." Since attributes of a subclass are not visible to the superclass, it won't work.
Or should it?
I mean, the sublass inherits the method, making it its own method. At design time, it is pretty clear that this method belongs to the super class. At runtime, it belongs to the instance, which is an instance of the sub class. I guess one could argue whether visibility should be determined by where the method is implemented or by wht type of an instance the method belongs to at runtime.
My understanding would prefer the latter.