Question

I'm playing around with implementing Spring AOP programmatically. I created a simple factory class that produces AOP Object.class proxies with a given list of MethodInterceptors:

public class AOPProxyFactoryBean implements FactoryBean<Object> {

    private List<MethodInterceptor> methodInterceptors = new ArrayList<MethodInterceptor>();

    public Object getObject() throws Exception {
        Object o = new Object();
        ProxyFactory proxyFactory = new ProxyFactory(o);
        for (MethodInterceptor methodInterceptor : methodInterceptors) {
            proxyFactory.addAdvice(methodInterceptor);
        }
        return proxyFactory.getProxy();
    }

    public Class<?> getObjectType() {
        return Object.class;
    }

    public boolean isSingleton() {
        return false;
    }

    public void setMethodInterceptors(List<MethodInterceptor> methodInterceptors) {
        this.methodInterceptors = methodInterceptors;
    }

A simple interceptor:

public class SimpleMethodInterceptor implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("SimpleMethodInterceptor: " + invocation.getMethod().getName());
        return invocation.proceed();
    }
}

Spring XML configuration:

<bean id="simpleMethodInterceptor" class="...SimpleMethodInterceptor"/>

<bean id="objectAOPProxyFactoryBean" class="...AOPProxyFactoryBean">
    <property name="methodInterceptors">
        <list>
            <ref bean="simpleMethodInterceptor"/>
        </list>
    </property>
</bean>

In the docs here you can read the following about addAdvice(Advice advice): '... Note that the given advice will apply to all invocations on the proxy, even to the toString() method!...'

So, I'm expecting to get all calls to Object.class methods intercepted by SimpleMethodInterceptor.

Test:

@Test
public void aopTest() {
    Object o = (Object) applicationContext.getBean("objectAOPProxyFactoryBean");
    o.toString();
    o.equals(o);
    o.getClass();
}

gives this output:

SimpleMethodInterceptor: toString

It seems that only toString() method got intercepted. Any idea why?

Was it helpful?

Solution

Odd. It seems like a bug to me. I can't explain why exactly, but I have a possible workaround. Create an interface and redefine equals and hashCode there:

public interface MadeUpInterface {
    @Override
    public boolean equals(Object obj);

    @Override
    public int hashCode();
}

Return that an instance that implements that interface from the proxy factory instead.

public Object getObject() throws Exception {
    Object o = new MadeUpInterface() {};
    ProxyFactory proxyFactory = new ProxyFactory(o);
    for (MethodInterceptor methodInterceptor : methodInterceptors) {
        proxyFactory.addAdvice(methodInterceptor);
    }
    return proxyFactory.getProxy();
}

Now it will print equals and hashCode. So I think the behavior is that it doesn't intercept calls for methods that are defined only on Object. And toString is treated as a special case.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top