Search code examples
javaspringspring-bootproxycglib

Nested Proxy using cglib in spring


Preface: I want to create a proxy of an existed proxy (Using cglib package in spring) , like when I call the original method class both methods of both proxies called first. Does it make any sense at all? or is it possible?

Problem: When I'm creating the second enhancer, i get the java.lang.ClassFormatError-->Duplicate method name "newInstance" with signature " exception.


Sample code is as follows

Original Class

public class OriginalClass {

    public void print(){
        System.out.println("MAIN METHOD");
    }

}

Create Two Proxies

public class Main {

    public static void main(String[] args) {

        //Create First Proxy
        Enhancer firstEnhancer= new Enhancer();
        firstEnhancer.setSuperclass(OriginalClass.class);
        firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
            return methodProxy.invokeSuper(o, objects);
        });
        OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();

        //Create Second Proxy
        Enhancer secondEnhancer= new Enhancer();
        secondEnhancer.setSuperclass(firstProxy.getClass());
        secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
            return methodProxy.invokeSuper(o, objects);
        });

        //Getting Exception on this line
        OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();

        //Call 
        secondProxy.print();
    }
}

The expected result is as follows (Print)

METHOD INTERCEPTOR AT SECOND PROXY
METHOD INTERCEPTOR AT FIRST PROXY
MAIN METHOD

But I get the below Exception (when creating the second proxy)

Caused by: java.lang.ClassFormatError: Duplicate method name "newInstance" with signature "([Lorg.springframework.cglib.proxy.Callback;)Ljava.lang.Object;" in class file com/test/OriginalClass$$EnhancerByCGLIB$$37b306ed$$EnhancerByCGLIB$$15133919

Real World Scenario

I want to wrap a proxy on all beans that have been proxied by spring, using BeanPostProcessors and cglib. For example, I want to wrap a proxy on all @transactional methods (log before and after the transactions).

Update: I prefer to create proxies, not AOPs.(AOP is itself a proxy)


Solution

  • I've found working soultion, it works when used methodProxy.invoke() instead of methodProxy.invokeSuper() in the second enhancer, also the firstProxy need to be passed to the invocation instead of the o object and the superClass is set to the original one, that doesn't have the newInstance method:

    public class Test {
         public static void main(String[] args) {
    
                //Create First Proxy
                Enhancer firstEnhancer= new Enhancer();
                firstEnhancer.setSuperclass(OriginalClass.class);
                firstEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
                    System.out.println("METHOD INTERCEPTOR AT FIRST PROXY");
                    return methodProxy.invokeSuper(o, objects);
                });
                OriginalClass firstProxy = (OriginalClass) firstEnhancer.create();
    
                //Create Second Proxy
                Enhancer secondEnhancer= new Enhancer();
                secondEnhancer.setSuperclass(firstProxy.getClass().getSuperclass());
                // secondEnhancer.setSuperclass(OriginalClass.class);
                secondEnhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
                    System.out.println("METHOD INTERCEPTOR AT SECOND PROXY");
                    return methodProxy.invoke(firstProxy, objects);
                });
    
                //Getting Exception on this line
                OriginalClass secondProxy = (OriginalClass) secondEnhancer.create();
    
                //Call 
                secondProxy.print();
            }
    }
    

    result:

    METHOD INTERCEPTOR AT SECOND PROXY
    METHOD INTERCEPTOR AT FIRST PROXY
    MAIN METHOD