As part of detecting side effects across tests, we needed to inspect some objects in tests autowired by spring. Unfortunately these objects were automatically proxied with the current configuration (and needed by some tests) so we needed some way of accessing the underlying proxied objects.
We didn’t really find many good examples of how to go about bypassing the spring proxies created through AOP. Doing a bit of debugging we found that spring used CGLib to generate its proxies and there is fortunately a method made accessible called getTargetSource()
that gives you the underlying object. Here’s the helper class we wrote to extract it.
public class CglibHelper { private final Object proxied; public CglibHelper(Object proxied) { this.proxied = proxied; } public Object getTargetObject() { String name = proxied.getClass().getName(); if (name.toLowerCase().contains("cglib")) { return extractTargetObject(proxied); } return proxied; } private Object extractTargetObject(Object proxied) { try { return findSpringTargetSource(proxied).getTarget(); } catch (Exception e) { throw new RuntimeException(e); } } private TargetSource findSpringTargetSource(Object proxied) { Method[] methods = proxied.getClass().getDeclaredMethods(); Method targetSourceMethod = findTargetSourceMethod(methods); targetSourceMethod.setAccessible(true); try { return (TargetSource)targetSourceMethod.invoke(proxied); } catch (Exception e) { throw new RuntimeException(e); } } private Method findTargetSourceMethod(Method[] methods) { for (Method method : methods) { if (method.getName().endsWith("getTargetSource")) { return method; } } throw new IllegalStateException( "Could not find target source method on proxied object [" + proxied.getClass() + "]"); } }
Very nice, was really useful. Thank you!
That was really helpful! Saved me a lot of time 🙂
Thank you so much!! This was very helpful for me 🙂
When searching for a way to “unproxy” Spring bean I first this solution but later found simpler and faster one. Since getTargetSource() is a method of Advised interface helper class can be rewriten as simple static method:
public static T unproxyBean(T possiblyProxiedObject) {
if (possiblyProxiedObject instanceof Advised) {
try {
return (T) ((Advised) possiblyProxiedObject).getTargetSource().getTarget();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return possiblyProxiedObject;
}
Thanks man! It solved my problem. Good job.
Thanks a lot ! It solved my problem. Very nice.