Java and Spring development

Pitfalls with aspect technologies

with 3 comments

Even though aspect technologies are very powerful. Especially to address cross-cutting concerns like transactions, it shouldn’t be used everywhere it’s possible.

The first part of this post consists of a simple example that uses AspectJ to return an unexpected value. The last part is about where aspects fits and where you should consider to avoid it.

A quote from the Spider-Man movie:

With great power comes great responsibility

This applies to some degree to aspect technologies too. Since it can change the behaviour of an application at compilation, startup or at runtime. Even without leaving a trace in the source code.

An aspect that changes the return value of String’s toLowerCase()

To demonstrate an unexpected result from a method, I have created a StringAspect with AspectJ that returns the opposite of what the method name says.

When some code calls on String‘s toLowerCase() method, the StringAspect below reroutes the call to String‘s toUpperCase() method instead:

@Aspect
public class StringAspect {

	@Pointcut("call(* String.toLowerCase())")
	public void toLowerCasePointcut() {}

	@Around("toLowerCasePointcut()")
	public String toLowerCaseAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {

//		String text = (String) joinPoint.proceed();
		String text = ((String) joinPoint.getTarget()).toUpperCase();

		return text;
	}
}

To get the expected result, you can remove the comment on the line with joinPoint.proceed() and remove the line below. Eventually remove the AspectJ compiler or the JVM agent to avoid weaving in the advice.

The test class that asserts that the String‘s toLowerCase() method works as expected:

public class StringTest {

	@Test
	public void testAroundAdvice() {
		String demoText = "tHiS iS a TeSt";

		assertEquals("this is a test", demoText.toLowerCase());
	}
}

Without AspectJ weaving, the test finishes successfully, but with weaving the result is:

org.junit.ComparisonFailure: expected:<[this is a test]> but was:<[THIS IS A TEST]>

Best practice from enterprise frameworks

Features like transaction handling, security and concurrency support are good candidates to be done with aspects. Spring, Guice and EJB implementations all use aspects to provide such enterprise capabilities without cluttering the application’s source code with infrastructure logic.

You can see this post for a good example. Best practice with Java 5 and later is to add an annotation on methods that will be intercepted.

Annotations that says this method should be executed asynchronously in a transaction:

@Async
@Transactional
public void demoMethod() {
	// logic ..
}

These annotations are excellent pointcuts for enterprise frameworks.

Cases where aspects should be avoided

To change the target method like the StringAspect above should be avoided. You can replace an instance with a mock/stub object with AspectJ. In situations where the called instance is an object of a final class that doesn’t implement any interfaces, then an aspect is your only choice. It mocks away the dependency, but refactoring the code and use a mocking framework should be the preferred choice. It makes the code much more readable.

Especially without a tool like AJDT that visualizes the joinpoints in the source code. Here’s an example with the AJDT Eclipse plugin.

You should be really careful about adding or changing any data inside an advice. Such modifications makes the code almost impossible to read and the chance for bugs are higher.

Else, if many of the developers in a team isn’t familiar with aspects, you should also limit the use since it adds “magic” to the application that only a few developers on the team can understand.

Advertisements

Written by Espen

June 5, 2010 at 17:11

Posted in Aspects

Tagged with

3 Responses

Subscribe to comments with RSS.

  1. Hi, very useful topic. I have a question, if you can help; I use spring and aspectj jars, when I run your code it gives me

    org.aspectj.weaver.tools.UnsupportedPointcutPrimitiveException: Pointcut expression call(* String.toLowerCase()) contains unsupported pointcut primitive ‘call’

    error. What am I doing wrong?

    asyardrd

    June 29, 2011 at 11:47

    • Thanks!

      I can’t see the error from your little code snippet. You should post a question on stackoverflow.com.

      Include the aspect class and tag it with aspectj and you should get an answer quite soon.

      Espen

      June 29, 2011 at 17:07

      • The question has been answered on stackoverflow.com here.

        Espen

        June 29, 2011 at 19:19


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: