CGLIB is not able to intercept methods in a superclass / superinterface

Maybe I don’t think too much, or the answer is really elusive. Quick script (try the code, it compiles).

Consider the legacy interface

public interface LegacyInterfaceNoCodeAvailable{ void logInfo(String message); } 

Consider the legacy interface implementation above

 public abstract class LegacyClassNoCodeAvailable implements LegacyInterfaceNoCodeAvailable{ public abstract void executeSomething(); public void rockItOldSchool(){ logInfo("bustin' chops, old-school style"); } @Override public void logInfo(String message){ System.out.println(message); } } 

Now I came as this ambitious person and wrote a class for the “new” system, but it works inside the “Legacy” framework, so I need to extend the base base class.

 public class lass SpankingShiny extends LegacyClassNoCodeAvailable{ public void executeSomething(){ rockItOldSchool(); logInfo("I'm the King around here now"); System.out.println("this new stuff rocks!!"); } } 

Everything works fine, as you expected:

 SpankingShiny shiny = new SpankingShiny(); shiny.executeSomething(); 

The above code gives (as expected):

 bustin' chops, old-school style I'm the King around here now this new stuff rocks!! 

Now, as you can see, "System.out.println ()" correctly prints the desired result. But I want to replace "System.out.println ()" with the logger.

Problem:

I cannot use the CGLIB proxy to intercept the "logInfo (string)" method and print its desired message through the logger (by the way, I configured the logging). This method call "apparently" does not get into the proxy.

code:

 public class SpankingShinyProxy implements MethodInterceptor{ private SpankingShiny realShiny; private final Logger logger = Logger.getLogger(SpankingShinyProxy.class); public SpankingShinyProxy(SpankingShiny realShiny) { super(); this.realShiny = realShiny; } @Override public Object intercept(Object proxyObj, Method proxyMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable { String methodName = proxyMethod.getName(); if("logInfo".equals(methodName)){ logger.info(methodParams[0]); } return proxyMethod.invoke(realShiny, methodParams); } public static SpankingShiny createProxy(SpankingShiny realObj){ Enhancer e = new Enhancer(); e.setSuperclass(realObj.getClass()); e.setCallback(new SpankingShinyProxy(realObj)); SpankingShiny proxifiedObj = (SpankingShiny) e.create(); return proxifiedObj; } } 

The main method:

 public static void main(String... args) { SpankingShiny shiny = new SpankingShiny(); shiny.executeSomething(); SpankingShiny shinyO = SpankingShinyProxy.createProxy(shiny); shinyO.executeSomething(); } 

The above code gives (NOT as expected):

 bustin' chops, old-school style I'm the King around here now this new stuff rocks!! bustin' chops, old-school style I'm the King around here now this new stuff rocks!! 

Where will I be wrong?

Thanks!

+6
source share
2 answers

Well, firstly, you are lucky that your proxy did not hit. If you were referring to the actual proxy server in intercept , you would get an infinite loop, since your reflective method will be sent by the same SpankingShinyProxy . Again and again.

The proxy server does not work, because you simply delegate the call to the executeSomething method to your proxy server for some non-professional object. You should not use realObj . All method calls must be sent by your proxy server, as well as method calls that are called using the most successful proxy server!

Change the last line in the intercept method to methodProxy.invokeSuper(proxyObj, args) . Then create your object using Enhancer . If your constructor for SpankingShiny does not need arguments, call create without any arguments if it is beautiful. Otherwise, put the objects that you usually supply to the constructor in the create method. Then use only the object you get from create , and you're good.

If you need more information about cglib, you can read this blog article: http://mydailyjava.blogspot.no/2013/11/cglib-missing-manual.html

+1
source

I had the same problem. In my case, realObj was the proxy itself (a Spring Bean - a @Component ).

So, I needed to change the .setSuperClass() part to:

 Enhancer e = new Enhancer(); e.setSuperclass(realObj.getClass()); e.setCallback(new SpankingShinyProxy(realObj)); SpankingShiny proxifiedObj = (SpankingShiny) e.create(); 

I changed:

 e.setSuperclass(realObj.getClass()); 

To:

 e.setSuperclass(realObj.getClass().getSuperClass()); 

This worked because, as said, realObj.getClass() was a CGLIB proxy, and this method returned a class generated by a crazy CGLIB name, for example abcMyClass$$EnhancerBySpringCGLIB$$1e18666c . When I added .getSuperClass() , it returned the class that it should have returned first.

0
source

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


All Articles