Reflection.proxy is not valid when overriding

It seems that reflection.proxy is not what is expected when there are overridden methods. In detail, starting with a simple application:

static void debug( String fmt, Object... args ) { System.out.println( String.format(fmt,args)); } interface I { void m1(); void m2(); } static class A implements I { public void m1() { System.out.println( "A.m1" ); m2(); } public void m2() { System.out.println( "A.m2" ); } } static class B extends A { @Override public void m2() { System.out.println( "B.m2" ); } } public static void main( String[] args ) { B b = new B(); b.m1(); } 

output, as expected:

 A.m1 B.m2 

Now we are trying to maximize the calls to all the "B b" methods. New code added:

 static public class HelloInvocationHandler implements InvocationHandler { I proxied; HelloInvocationHandler( I proxied ) { this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); debug( "HelloInvocationHandler: invoke method %s", methodName); return method.invoke(proxied,args); } } public static void main( String[] args ) { B b = new B(); HelloInvocationHandler handler = new HelloInvocationHandler(b); I pb = (I) Proxy.newProxyInstance( I.class.getClassLoader(), new Class[] { I.class }, handler); pb.m1(); } 

and new output:

 HelloInvocationHandler: invoke method m1 A.m1 B.m2 

as you can see, the m2 call is not made through the proxy. If all calls to Method B were associated with a proxy server, the line string "HelloInvocationHandler: invoke method m2" should appear in the output.

Any clues?

Thanks.

-1
source share
3 answers

You can use the CGLib library to create proxies. Use Enhancer.create(B.class, new HelloInvocationHandler()) to intercept method calls. This is no more complicated than using the JDK Proxy , but much more flexible. Should help in your case. The interceptor should be implemented as follows:

 public class HelloInvocationHandler implements MethodInterceptor { public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { debug( "HelloInvocationHandler: invoke method %s", method.getName()); return methodProxy.invokeSuper(object, args); } } 

Use it as follows:

 B pb = (B)Enhancer.create(B.class, new HelloInvocationHandler()); pb.m1(); 
+3
source

Tagir got a solution, I have an explanation: the proxy does not "stick". Inside the method.invoke(proxied,args) control method.invoke(proxied,args) normal Java bytecode is set. Now this will be proxied , so this.m2() will call the method from B

It is not possible to use the JDK Proxy to intercept all method calls inside the class for which you created a proxy server. The reason for this is that Proxy is a hack: it just mimics what is needed to call methods on the proxy. This does not actually change the code of the Java base classes. Therefore, when this is a proxy server, method calls will be routed through InvocationHandler.invoke() . Once the code leaves this method, the usual Java rules apply.

To make this even simpler, your code above is equivalent:

 class HelloInvocationHandler implements I { I delegate; HelloInvocationHandler(I delegate ) { this.delegate = delegate; } public void m1() { delegate.m1(); } public void m2() { delegate.m2(); } } 

In this case, it is very easy to understand why calling m2() inside delegate.m1() does not call HelloInvocationHandler.m2() .

+2
source

That's right, only pb is a proxy class, a call to B.m2() is done inside HelloInvocationHandler.invoke with normal Method.invoke .

0
source

Source: https://habr.com/ru/post/986964/


All Articles