Wednesday 19 April 2017

Create dynamic proxy persistently in Java and ABAP

In my blog Implement CGLIB in ABAP I demonstrate how to create dynamical proxy class via CGLIB in Java and ABAP. The generated proxy class is actually a subclass which inherits the base class. Such class created by CGLIB is transient, which means the life time of generated class is only within the current session where it is created, which will not be persisted.

In this blog I will show how to create a globally persistent proxy class dynamically in Java and ABAP.

The example is built based on Proxy design pattern.

Dynamic proxy in Java


There is one interface:

public interface IHelloWorld
{
    void print();
}

And one implementation class:

class HelloWorldImp implements IHelloWorld
{
    public void print()
    {
        System.out.println("Hello World");
    }
}

Then I will create a dynamic proxy class ( which will be persisted to my laptop ) based on HelloWorldImp, with additional line System.out.println(\”Before Hello World!\”); before original method print() and System.out.println(\”After Hello World!\”); after method print().
The class object of generated proxy class is created via the following method which consists of four steps:

private static Class<?> getProxyClass() {
String sourceCode = getSourceCode();
String javaFile = createJavaFile(sourceCode);
compile(javaFile);
return loadClass();
}

step1: populate source code of proxy class

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

step2: create a new .java file in disk with source code generated in previous step:

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

step3: compile the generated .java file in step 2 via API exposed by interface in package javax.tools.JavaCompiler, after compilation .class file will be generated in disk.

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

step4: use URLClassLoader to load the generated .class file in step3. After that it is available to create a new instance based on this loaded class via reflection.

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

Here below is the code how to consume this getProxyClass() method:

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

Once the above code is executed, you can observe:

1. The original method of print is successfully enhanced via generated proxy class:

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

2. corresponding .java and .class are persisted in the disk.

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

The complete source code of this example could be found from my github.

Dynamic proxy in ABAP


Again there is an interface IF_HELLOWORLD and an implementation class CL_HELLOWORLD based on which a new proxy class will be created dynamically.

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

Let’s first see what could be achieved in ABAP:

zcl_abap_dynamic_proxy_factory=>get_proxy(
  EXPORTING
   io_origin = NEW cl_helloworld( )
   iv_new_class_name = 'ZCLABAP'
   iv_pre_exit  = `WRITE:/ 'Before hello world'.`
   iv_post_exit = `WRITE:/ 'After hello world'.`
  RECEIVING
   ro_proxy = DATA(proxy) ).

DATA(lo_helloworld) = CAST if_helloworld( proxy ).

lo_helloworld->print( ).

1. The original instance of class CL_HELLOWORLD is passed to GET_PROXY method. Inside this method, it will inject the pre exit and post exit logic into the original implementation of print method. The injection is done in a new class, whose name is passed via parameter iv_new_class_name, in this example, ZCLABAP.

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

2. Once the above report is executed, the injected proxy instance returned in line 10 contains the enhanced logic so as expected you can now see the ABAP statement passed in iv_pre_exit and iv_post_exit are executed.

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

And you can also open the generated proxy class in SE24:

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

The pre exit and post exit logic are injected here:

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

The complete source code of ZCL_ABAP_DYNAMIC_PROXY_FACTORY could be found from my github.

Brief explanation about main logic of dynamic proxy generation


1. extract_interface_info
extract the involved interface name and the name of method to be injected via RTTI against passed reference via parameter io_origin

2. prepare_source_code
Inject the pre exit and post exit statement into method source code internal table.

3. prepare_attr_and_signature
Prepare method signature and private attribute for new class

4. generate_class
Call ABAP class generation function module based on metadata assembled by previous two steps.

SAP ABAP Tutorials and Materials, SAP ABAP Guide, SAP ABAP Certifications

No comments:

Post a Comment