该工具类负责生产一个新的具有持久化存储的静态代理类:
class ZCL_ABAP_DYNAMIC_PROXY_FACTORY definition
public
final
create public .
public section.
class-methods GET_PROXY
importing
!IO_ORIGIN type ref to OBJECT
!IV_NEW_CLASS_NAME type STRING
!IV_PRE_EXIT type STRING
!IV_POST_EXIT type STRING
returning
value(RO_PROXY) type ref to OBJECT .
protected section.
private section.
class-data MS_VSEOCLASS type VSEOCLASS .
class-data MT_ATTRIBUTE type SEOO_ATTRIBUTES_R .
class-data MT_IMP_IF type SEOR_IMPLEMENTINGS_R .
class-data MT_METHODS type SEOO_METHODS_R .
class-data MT_PARAMETERS type SEOS_PARAMETERS_R .
class-data MV_INTERFACE_NAME type STRING .
class-data MV_METHOD_NAME type STRING .
class-data MT_SOURCECODE type SEO_METHOD_SOURCE_TABLE .
class-data MV_NEW_CLASS_NAME type STRING .
class-data MO_ORIGIN type ref to OBJECT .
class-data MV_PRE_EXIT type STRING .
class-data MV_POST_EXIT type STRING .
class-methods GENERATE_CLASS .
class-methods PREPARE_ATTR_AND_SIGNATURE .
class-methods PREPARE_SOURCE_CODE .
class-methods EXTRACT_INTERFACE_INFO
importing
!IO_ORIGIN type ref to OBJECT .
class-methods INIT
importing
!IV_NEW_CLASS_NAME type STRING
!IO_ORIGIN type ref to OBJECT
!IV_PRE_EXIT type STRING
!IV_POST_EXIT type STRING .
class-methods CREATE_INSTANCE
returning
value(RO_PROXY) type ref to OBJECT .
ENDCLASS.
CLASS ZCL_ABAP_DYNAMIC_PROXY_FACTORY IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_DYNAMIC_PROXY_FACTORY=>CREATE_INSTANCE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RO_PROXY TYPE REF TO OBJECT
* +--------------------------------------------------------------------------------------</SIGNATURE>
method CREATE_INSTANCE.
TRY.
create object ro_proxy type (mv_new_class_name)
EXPORTING
io_origin = mo_origin.
CATCH cx_root INTO data(cx_root).
WRITE:/ 'instance created failed: ', cx_root->get_text( ).
ENDTRY.
endmethod.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_DYNAMIC_PROXY_FACTORY=>EXTRACT_INTERFACE_INFO
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_ORIGIN TYPE REF TO OBJECT
* +--------------------------------------------------------------------------------------</SIGNATURE>
method EXTRACT_INTERFACE_INFO.
data(lo_class) = cast CL_ABAP_OBJECTDESCR( cl_abap_objectdescr=>describe_by_object_ref( io_origin ) ).
READ TABLE lo_class->interfaces INTO mv_interface_name INDEX 1 .
CHECK sy-subrc = 0.
"For demo purpose, I assume only one method in one interface
SELECT SINGLE cmpname INTO mv_method_name FROM seocompo
WHERE clsname = mv_interface_name.
endmethod.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_DYNAMIC_PROXY_FACTORY=>GENERATE_CLASS
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD generate_class.
CALL FUNCTION 'SEO_CLASS_CREATE_COMPLETE'
EXPORTING
devclass = '$TMP'
version = seoc_version_active
authority_check = abap_true
overwrite = abap_true
suppress_method_generation = abap_false
genflag = abap_false
method_sources = mt_sourcecode
suppress_dialog = abap_true
CHANGING
class = ms_vseoclass
methods = mt_methods
parameters = mt_parameters
implementings = mt_imp_if
attributes = mt_attribute
EXCEPTIONS
existing = 1
is_interface = 2
db_error = 3
component_error = 4
no_access = 5
other = 6
OTHERS = 7.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_ABAP_DYNAMIC_PROXY_FACTORY=>GET_PROXY
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_ORIGIN TYPE REF TO OBJECT
* | [--->] IV_NEW_CLASS_NAME TYPE STRING
* | [--->] IV_PRE_EXIT TYPE STRING
* | [--->] IV_POST_EXIT TYPE STRING
* | [<-()] RO_PROXY TYPE REF TO OBJECT
* +--------------------------------------------------------------------------------------</SIGNATURE>
method GET_PROXY.
init( iv_new_class_name = iv_new_class_name io_origin = io_origin
iv_pre_exit = iv_pre_exit iv_post_exit = iv_post_exit ).
extract_interface_info( io_origin ).
prepare_source_code( ).
prepare_attr_and_signature( ).
generate_class( ).
ro_proxy = create_instance( ).
endmethod.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_DYNAMIC_PROXY_FACTORY=>INIT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_NEW_CLASS_NAME TYPE STRING
* | [--->] IO_ORIGIN TYPE REF TO OBJECT
* | [--->] IV_PRE_EXIT TYPE STRING
* | [--->] IV_POST_EXIT TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
method INIT.
clear: mv_interface_name, mv_method_name, mt_sourcecode,mt_sourcecode,
mt_imp_if, ms_vseoclass, mt_attribute,mt_parameters,mt_methods.
mv_new_class_name = iv_new_class_name.
mo_origin = io_origin.
mv_pre_exit = iv_pre_exit.
mv_post_exit = iv_post_exit.
endmethod.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_DYNAMIC_PROXY_FACTORY=>PREPARE_ATTR_AND_SIGNATURE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD prepare_attr_and_signature.
DATA:ls_attribute LIKE LINE OF mt_attribute,
ls_parameter LIKE LINE OF mt_parameters,
ls_method LIKE LINE OF mt_methods.
ls_method-clsname = mv_new_class_name.
ls_method-cmpname = 'CONSTRUCTOR'.
ls_method-state = 1. "implemented
ls_method-exposure = 2. "public
APPEND ls_method TO mt_methods.
ls_parameter-clsname = mv_new_class_name.
ls_parameter-cmpname = 'CONSTRUCTOR'.
ls_parameter-version = 1.
ls_parameter-descript = 'Constructor automatically generated by Jerry'.
ls_parameter-type = 'OBJECT'."mv_interface_name.
ls_parameter-sconame = 'IO_ORIGIN'.
ls_parameter-cmptype = 1. "METHOD
ls_parameter-mtdtype = 0. "METHOD
ls_parameter-pardecltyp = 0. "IMPORTING
ls_parameter-parpasstyp = 1. "pass by reference
ls_parameter-typtype = 3. "type ref to
APPEND ls_parameter TO mt_parameters.
ls_attribute-clsname = mv_new_class_name.
ls_attribute-cmpname = 'MO_ORIGIN'.
ls_attribute-state = 1.
ls_attribute-attdecltyp = 0.
ls_attribute-attexpvirt = 0. "private
ls_attribute-typtype = 3. "type ref to
ls_attribute-type = 'OBJECT'."mv_interface_name.
APPEND ls_attribute TO mt_attribute.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_DYNAMIC_PROXY_FACTORY=>PREPARE_SOURCE_CODE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD prepare_source_code.
DATA: ls_method_source TYPE seo_method_source,
ls_imp_if TYPE seor_implementing_r,
ls_imp_det TYPE seoredef.
ms_vseoclass-clsname = mv_new_class_name.
ms_vseoclass-state = seoc_state_implemented.
ms_vseoclass-exposure = seoc_exposure_public.
ms_vseoclass-descript = `Dynamic proxy generated by Jerry's code`.
ms_vseoclass-langu = sy-langu.
ms_vseoclass-clsccincl = abap_true.
ms_vseoclass-unicode = abap_true.
ms_vseoclass-fixpt = abap_true.
ms_vseoclass-clsfinal = abap_true.
ls_imp_det = ls_imp_if-clsname = mv_new_class_name.
ls_imp_det = ls_imp_if-refclsname = mv_interface_name.
ls_imp_if-state = seoc_state_implemented.
APPEND ls_imp_if TO mt_imp_if.
CLEAR: ls_method_source.
DATA: lv_name TYPE string.
ls_method_source-cpdname = |{ mv_interface_name }~{ mv_method_name }|.
APPEND |{ mv_pre_exit }| TO ls_method_source-source.
APPEND |DATA(lo) = CAST { mv_interface_name }( mo_origin ).| to ls_method_source-source.
APPEND 'lo->print( ).' TO ls_method_source-source.
APPEND |{ mv_post_exit }| TO ls_method_source-source.
APPEND ls_method_source TO mt_sourcecode.
CLEAR: ls_method_source.
ls_method_source-cpdname = 'CONSTRUCTOR'.
APPEND 'mo_origin = io_origin.' TO ls_method_source-source.
APPEND ls_method_source TO mt_sourcecode.
ENDMETHOD.
ENDCLASS.
这个类是Jerry仿照Java CGLIB(Code Generation Library)创建的, 针对传入的一个ABAP类,能创建一个生命周期只有当前会话(current session)内的代理类,该代理类是传入ABAP类的子类。这意味着传入的ABAP类必须能够被继承,不能被标记为final.
CLASS zcl_abap_cglib_tool DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
CLASS-METHODS get_proxy
IMPORTING
!iv_class_name TYPE string
!io_pre_exit TYPE REF TO if_preexit
!io_post_exit TYPE REF TO if_postexit
RETURNING
VALUE(ro_proxy) TYPE REF TO object .
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-DATA mv_class_name TYPE string .
CLASS-DATA mt_source TYPE seop_source_string .
CLASS-DATA mo_proxy TYPE REF TO object .
CLASS-DATA mo_preexit TYPE REF TO if_preexit .
CLASS-DATA mo_postexit TYPE REF TO if_postexit .
CLASS-METHODS generate_proxy .
CLASS-METHODS get_source_code .
ENDCLASS.
CLASS ZCL_ABAP_CGLIB_TOOL IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_CGLIB_TOOL=>GENERATE_PROXY
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD generate_proxy.
DATA(lv_new_cls_name) = mv_class_name && '_SUB'.
DATA(lv_inherit) = |inheriting from { mv_class_name }|.
TRANSLATE lv_new_cls_name TO UPPER CASE.
TRY.
LOOP AT mt_source ASSIGNING FIELD-SYMBOL(<source1>) WHERE table_line CS mv_class_name.
REPLACE mv_class_name IN <source1> WITH lv_new_cls_name.
ENDLOOP.
LOOP AT mt_source ASSIGNING FIELD-SYMBOL(<source>) WHERE table_line CS mv_class_name.
DELETE mt_source INDEX ( sy-tabix + 1 ).
INSERT lv_inherit INTO mt_source INDEX ( sy-tabix + 1 ).
EXIT.
ENDLOOP.
GENERATE SUBROUTINE POOL mt_source NAME DATA(prog).
WRITE: / sy-subrc.
DATA(class) = |\\PROGRAM={ prog }\\CLASS={ lv_new_cls_name }|.
CREATE OBJECT mo_proxy TYPE (class).
CALL METHOD mo_proxy->('SET_PREEXIT')
EXPORTING
io_preexit = mo_preexit.
CALL METHOD mo_proxy->('SET_POSTEXIT')
EXPORTING
io_postexit = mo_postexit.
CATCH cx_root INTO DATA(cx_root).
WRITE: / cx_root->get_text( ).
ENDTRY.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_ABAP_CGLIB_TOOL=>GET_PROXY
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_CLASS_NAME TYPE STRING
* | [--->] IO_PRE_EXIT TYPE REF TO IF_PREEXIT
* | [--->] IO_POST_EXIT TYPE REF TO IF_POSTEXIT
* | [<-()] RO_PROXY TYPE REF TO OBJECT
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_proxy.
mv_class_name = iv_class_name.
mo_preexit = io_pre_exit.
mo_postexit = io_post_exit.
CLEAR: mo_proxy.
get_source_code( ).
generate_proxy( ).
ro_proxy = mo_proxy.
ENDMETHOD.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_ABAP_CGLIB_TOOL=>GET_SOURCE_CODE
* +-------------------------------------------------------------------------------------------------+
* +--------------------------------------------------------------------------------------</SIGNATURE>
METHOD get_source_code.
DATA:
cifkey TYPE seoclskey,
clstype TYPE seoclstype,
source TYPE seop_source_string,
pool_source TYPE seop_source_string,
l_string TYPE string,
source_line TYPE LINE OF seop_source_string,
tabix TYPE sytabix,
includes TYPE seop_methods_w_include,
include TYPE seop_method_w_include,
cifref TYPE REF TO if_oo_clif_incl_naming,
clsref TYPE REF TO if_oo_class_incl_naming,
intref TYPE REF TO if_oo_interface_incl_naming.
cifkey-clsname = mv_class_name.
CALL METHOD cl_oo_include_naming=>get_instance_by_cifkey
EXPORTING
cifkey = cifkey
RECEIVING
cifref = cifref
EXCEPTIONS
OTHERS = 1.
ASSERT sy-subrc = 0.
APPEND 'program.' TO mt_source.
CHECK cifref->clstype = seoc_clstype_class.
clsref ?= cifref.
READ REPORT clsref->class_pool INTO pool_source.
READ REPORT clsref->locals_old INTO source.
LOOP AT source INTO source_line.
IF source_line NS '*"*'.
APPEND source_line TO mt_source..
ENDIF.
ENDLOOP.
READ REPORT clsref->locals_def INTO source.
LOOP AT source INTO source_line.
IF source_line NS '*"*'.
APPEND source_line TO mt_source..
ENDIF.
ENDLOOP.
READ REPORT clsref->locals_imp INTO source.
LOOP AT source INTO source_line.
IF source_line NS '*"*'.
APPEND source_line TO mt_source..
ENDIF.
ENDLOOP.
READ REPORT clsref->public_section INTO source.
LOOP AT source ASSIGNING FIELD-SYMBOL(<source_line>).
IF <source_line> NS '*"*'.
FIND REGEX '.*methods.*\.' IN <source_line> MATCH LENGTH DATA(lv_len).
IF sy-subrc = 0.
lv_len = lv_len - 1.
<source_line> = <source_line>+0(lv_len).
CONCATENATE <source_line> 'redefinition' '.' INTO <source_line> SEPARATED BY space.
ENDIF.
APPEND <source_line> TO mt_source.
ENDIF.
ENDLOOP.
APPEND 'methods SET_PREEXIT importing !IO_PREEXIT type ref to IF_PREEXIT .' TO mt_source.
APPEND 'methods SET_POSTEXIT importing !IO_POSTEXIT type ref to IF_POSTEXIT .' TO mt_source.
READ REPORT clsref->protected_section INTO source.
LOOP AT source INTO source_line.
IF source_line NS '*"*'.
APPEND source_line TO mt_source.
ENDIF.
ENDLOOP.
READ REPORT clsref->private_section INTO source.
LOOP AT source INTO source_line.
IF source_line NS '*"*'.
APPEND source_line TO mt_source.
ENDIF.
ENDLOOP.
APPEND 'data MO_PREEXIT type ref to IF_PREEXIT .' TO mt_source.
APPEND 'data MO_POSTEXIT type ref to IF_POSTEXIT .' TO mt_source.
CONCATENATE 'CLASS' cifkey 'IMPLEMENTATION' INTO l_string SEPARATED BY space.
LOOP AT pool_source FROM tabix INTO source_line.
IF source_line CS 'ENDCLASS'.
APPEND source_line TO mt_source..
ENDIF.
IF source_line CS l_string.
SKIP.
APPEND source_line TO mt_source..
tabix = sy-tabix.
EXIT.
ENDIF.
ENDLOOP.
includes = clsref->get_all_method_includes( ).
LOOP AT includes INTO include.
READ REPORT include-incname INTO source.
INSERT 'mo_preexit->execute( ).' INTO source INDEX 2.
INSERT 'mo_postexit->execute( ).' INTO source INDEX ( lines( source ) ).
LOOP AT source INTO source_line.
APPEND source_line TO mt_source..
ENDLOOP.
ENDLOOP.
APPEND 'method set_preexit. mo_preexit = IO_PREEXIT. endmethod.' TO mt_source.
APPEND 'method set_postexit. mo_postexit = IO_POSTEXIT. endmethod.' TO mt_source.
LOOP AT pool_source FROM tabix INTO source_line.
IF source_line CS 'ENDCLASS'.
APPEND source_line TO mt_source..
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.