Milos Zikic - Personal site, sharing thoughts about startups, products and engineering

Spring AOP and Tomcat load-time weaving

Recently I've encountered a problem with storing null values for foreign keys into database from Flex. BlazeDS converts Number and int values to 0 if they are NaN or null so I was getting foreign key errors.

The solution for this is to intercept all the places where this is needed. In order to follow DRY philosophy I decided to utilize spring with AspectJ AOP in order to solve this problem.

Since our dto Java classes are not accessed through spring application context it is not possible to use pure spring AOP for this task. In order to make this work we need to use AspectJ compiler/weaver.

Spring ships with a small AspectJ aspect library spring-aspects.jar which you have to include in your classpath. The spring-aspects.jar contains an annotation-driven aspect that exploits this
capability to allow dependency injection of any object. The support is intended to be used for objects created
outside of the control of any container
which is this case.

The @Configurable annotation marks a class as eligible for Spring-driven configuration.

I am gonna show this on simple class example:

Car.java:

package com.myapp;
import org.springframework.beans.factory.annotation.Configurable;

@Configurable
public class Car {
private Integer id;

@NullAllowed
public void setId(Integer id){
this.id = id;
}
}


In order to easy isolate methods to which I want to apply my advice I will create simple annotitation to annotiate the methods for which I want to set the id to null if its value is 0.


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface NullAllowed {

}



And the aspect:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class NullAlowedAspect {

@Around(value="@annotation(com.myapp.NullAllowed) && args(intValue)")
public void nullInteger(ProceedingJoinPoint pjp,Integer intValue) throws Throwable{

if (intValue != null && intValue == 0){
intValue = null;
pjp.proceed(new Object[]{intValue});
} else {
pjp.proceed(new Object[]{intValue});
}

}

}


Ok, we now need to configure spring and tomcat for weaving.

1. create file WEB-INF/aop.xml to inform the AspectJ weaver that we want to weave
our NullAlowedAspect into our classes

<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver>
<!-- only weave classes in our application-specific packages -->
<include within="com.myapp.dto.*" />
</weaver>
<aspects>
<!-- weave in just this aspect -->
<aspect name="com.myapp.NullAlowedBeforeAdvice" />
</aspects>
</aspectj>


2. add to your spring applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<aop:aspectj-autoproxy />
<context:load-time-weaver/><!--

...
</beans>


3. put in your $CATALINA_BASE$/lib folder (Tomcat 6) spring-tomcat-weaver.jar

4. create file META-INF/context.xml

<Context path="/myapp">
<Loader
loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
useSystemClassLoaderAsParent="false" />
</Context>


5. now you can run your project and test it!

Comments

Miloš Žikić
Heh thanks guys. I'll tend to fill this up with more and more content, just to discipline myself enough :)
Anonymous
Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!
Matt
This worked great for me. Thanks for the help as I don't know how I'd have figured this out from the light documentation that is around.
Miloš Žikić
spring-tomcat-weaver.jar should be in $CATALINA_BASE/lib,
spring-aspects.jar, aspectjrt.jar, aspectjweaver.jar in your WEB-INF/lib.

This is the configuration I use also and this is tested on Tomcat 6.

Hope that it will work now.
Carlos
Well i tried to put spring-agent.jar,spring-aspects.jar and spring-tomcat-weaver.jar in my WEB-INF/lib dir and in my $CATALINA_BASE/lib.

But i am still getting the same error, i am using Tomcat 6 running through my eclipse.... Do u have any idea what is going on??

Thanks
Miloš Žikić
Hello Carlos,

You didn't follow the instruction totaly..

You should put the spring-aspects.jar lib in your classpath. This is noted in 4th paragraph:
" Spring ships with a small AspectJ aspect library spring-aspects.jar ..."
Carlos
Hello i have tried to follow exactly your example but i get the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.context.weaving.AspectJWeavingEnabler#0': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [org.apache.catalina.loader.WebappClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:spring-agent.jar


Can u help me?

thanks
Miloš Žikić
it can be on both places. Either WEB-INF or META-INF

For a simple web project I usually put it in a WEB-INF folder.
Eco-nemesis
Shouldnt aop.xml be under META-INF/ ?

Share this post