patkua@work

Finding real object under spring proxies

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() + "]");
    }
}

Exit mobile version