Thursday, April 12, 2007

Spring AOP and Legacy code

I am just coming of a very interesting project where we got to build an MVC layer on top of some existing code base. This project was fun, dynamic and we ended up doing a lot of slick work using Spring 2.0.x, Web Flow 1.0.x, Maven and it was good :)

One of the major requirements for the client was an ability to run legacy code base in parallel with shiny new MVC enabled application. After examining that legacy code base, we decided to stay away from trying to modify it at all cost. It was one of: touch here, feel consequences in modules that you did not know existed type situations. Lots of static methods, statefull services and super evil singletons. But we needed a way to use those legacy objects in Spring DI. Spring 2.0 Request scope to the rescue! Wow what a huge addition and helper.

<bean id="scopedBean" class="com.some.comp.ScopedBean" scope="request">
<aop:scoped-proxy>
</aop:scoped-proxy>
</bean>

After prototyping for a while one of my colleagues ran into ClassCastException that he couldn't recreate consistently. After digging around for a little bit I found the culprit. Down in the bowels of that legacy code base, object that we had scoped at the request in the Spring configuration was cast to the implementation/subtype. Big no no. Scoped beans are CGLib proxys and can't be cast. That was a terrible feeling for about a min or two until I remembered about Spring's Advised interface.
From Advised javadoc:
Any AOP proxy obtained from Spring can be cast to this interface to allow manipulation of its AOP advice.

Sight of relief and this code followed:

public static Object unwrapProxy(Object proxy) throws Exception {
if (AopUtils.isAopProxy(proxy)) {
return ((Advised) proxy)
.getTargetSource()
.getTarget();
}
return proxy;
}


The moral of the story: Be careful when playing with new and shinny in a legacy sandbox.