CL_ABAP_*DESCR
-classes and the DESCRIBE
statement. To get information on a class for example you might have seen code like this:DATA(lo_descr) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( 'LCL_TEST' ) ).
Class clazz = TestClass.class; // Java
Type type = typeof(TestClass); // C#
CL_ABAP_CLASSDESCR
instance where renaming the class using refactoring assistance does not lead to a runtime error.INSTANCE OF
logical expression in ABAP 7.50NEW
operator for object instance creation in ABAP 7.40DATA
variable declarationTYPES
type definitionFIELD-SYMBOL
declarationclassname=>member
CLASS lcl_test DEFINITION.
PUBLIC SECTION.
CONSTANTS:
gc_classname TYPE abap_classname VALUE 'LCL_TEST'.
ENDCLASS.
DATA(lo_descr2) = CAST cl_abap_classdescr(
cl_abap_typedescr=>describe_by_name( lcl_test=>gc_classname )
).
DATA: lo_dummy TYPE REF TO lcl_test.
DATA(lo_descr3) = CAST cl_abap_classdescr(
CAST cl_abap_refdescr(
cl_abap_typedescr=>describe_by_data( lo_dummy )
)->get_referenced_type( )
).
describe_by_data
method of the RTTI API and navigate and cast your way towards the class descriptor. It must be pointed out that describe_by_object_ref
does not work because you would need an instance of your class for that (REFERENCE_IS_INITIAL-exception), so you need to take the detour using cl_abap_refdescr
.VALUE
inline statement.TYPES: lty_ref TYPE REF TO lcl_test.
DATA(lo_descr4) = CAST cl_abap_classdescr(
CAST cl_abap_refdescr(
cl_abap_typedescr=>describe_by_data( VALUE lty_ref( ) )
)->get_referenced_type( )
).
DATA(lo_descr) = lcl_reflection_helper=>get_objectdescr_from_data( lo_dummy ).
CLASS lcl_test DEFINITION.
PUBLIC SECTION.
DATA:
mv_member TYPE i.
ENDCLASS.
ASSIGN lcl_test=>('MV_MEMBER') TO FIELD-SYMBOL(<lg_pointer>).
ASSERT <lg_pointer> IS ASSIGNED.
WRITE <lg_pointer>.
INTERFACE lif_member_publisher.
TYPES:
gty_attribute_name_tab TYPE SORTED TABLE OF abap_attrname WITH UNIQUE KEY table_line.
METHODS:
get_published_members RETURNING VALUE(rt_members) TYPE gty_attribute_name_tab.
ENDINTERFACE.
CLASS lcl_test DEFINITION.
PUBLIC SECTION.
INTERFACES:
lif_member_publisher.
ALIASES:
get_published_members FOR lif_member_publisher~get_published_members.
DATA:
mv_member TYPE i.
ENDCLASS.
CLASS lcl_test IMPLEMENTATION.
METHOD get_published_members.
rt_members = VALUE #( ( CONV #( 'MV_MEMBER' ) ) ).
ENDMETHOD.
ENDCLASS.
DATA(lo_test) = NEW lcl_test( ).
LOOP AT lo_test->get_published_members( ) ASSIGNING FIELD-SYMBOL(<lv_member_name>).
ASSIGN lo_test->(<lv_member_name>) TO FIELD-SYMBOL(<lg_pointer>).
ASSERT <lg_pointer> IS ASSIGNED.
WRITE: / |{ <lv_member_name> }: { <lg_pointer> }|.
ENDLOOP.
ASSERT <lg_pointer> IS ASSIGNED
if the member identifier is changed while the literal is not and again refactoring utilities cannot statically find this usage.nameof
(documentation). C# especially needs it because of data bindings in XAML / using the MVVM pattern.TYPE REF TO data
) that are type compatible the logical expression will be true if they point to the same data object (source). So one can just compare all member variables of a class with a given one and where the expression is true that is the searched member.CLASS lcl_test IMPLEMENTATION.
METHOD get_published_members.
DATA(lr_ref) = REF #( mv_member ).
DATA(lo_descr) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_object_ref( me ) ).
LOOP AT lo_descr->attributes ASSIGNING FIELD-SYMBOL(<ls_attr>).
ASSIGN me->(<ls_attr>-name) TO FIELD-SYMBOL(<lg_pointer>).
ASSERT <lg_pointer> IS ASSIGNED.
IF lr_ref = REF #( <lg_pointer> ).
rt_members = VALUE #( ( <ls_attr>-name ) ).
EXIT.
ENDIF.
UNASSIGN <lg_pointer>.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
CLASS lcl_test IMPLEMENTATION.
METHOD get_published_members.
rt_members = VALUE #(
( lcl_reflection_helper=>name_of( io_container = me ir_ref = REF #( mv_member ) ) )
).
ENDMETHOD.
ENDCLASS.
"! Reflection tools
CLASS lcl_reflection_helper DEFINITION.
PUBLIC SECTION.
CLASS-METHODS:
"! Get objectdescriptor from data variable
"! @parameter ig_data | Variable typed as REF TO interface/class
"! @parameter ro_descriptor | Object descriptor
"! @raising lcx_illegal_argument | ig_data does not refer to a class / interface
get_objectdescr_from_data IMPORTING ig_data TYPE any
RETURNING VALUE(ro_descriptor) TYPE REF TO cl_abap_objectdescr
RAISING lcx_illegal_argument,
"! Get the identifier of a public variable
"! @parameter ir_ref | Reference to the variable
"! @parameter io_container | Containing object instance
"! @parameter rv_name | Identifier of the data object
"! @raising lcx_illegal_argument | Argument cannot be null
name_of IMPORTING ir_ref TYPE REF TO data
io_container TYPE REF TO object
RETURNING VALUE(rv_name) TYPE abap_attrname
RAISING lcx_illegal_argument.
ENDCLASS.
CLASS lcl_reflection_helper IMPLEMENTATION.
METHOD get_objectdescr_from_data.
DATA(lo_descr) = cl_abap_typedescr=>describe_by_data( ig_data ).
IF lo_descr->type_kind <> cl_abap_typedescr=>typekind_oref.
RAISE EXCEPTION TYPE lcx_illegal_argument.
ENDIF.
DATA(lo_referenced_descr) = CAST cl_abap_refdescr( lo_descr )->get_referenced_type( ).
IF lo_referenced_descr->type_kind <> cl_abap_typedescr=>typekind_class
AND lo_referenced_descr->type_kind <> cl_abap_typedescr=>typekind_intf.
RAISE EXCEPTION TYPE lcx_illegal_argument.
ENDIF.
ro_descriptor = CAST cl_abap_objectdescr( lo_referenced_descr ).
ENDMETHOD.
METHOD name_of.
IF io_container IS NOT BOUND OR ir_ref IS NOT BOUND.
RAISE EXCEPTION TYPE lcx_illegal_argument.
ENDIF.
DATA(lo_descr) = CAST cl_abap_objectdescr(
cl_abap_typedescr=>describe_by_object_ref( io_container )
).
LOOP AT lo_descr->attributes ASSIGNING FIELD-SYMBOL(<ls_attr>)
WHERE visibility = cl_abap_objectdescr=>public.
ASSIGN io_container->(<ls_attr>-name) TO FIELD-SYMBOL(<lg_pointer>).
ASSERT <lg_pointer> IS ASSIGNED.
IF ir_ref = REF #( <lg_pointer> ).
rv_name = <ls_attr>-name.
EXIT.
ENDIF.
UNASSIGN <lg_pointer>.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
6 | |
5 | |
4 | |
3 | |
2 | |
2 | |
1 | |
1 | |
1 | |
1 |