Aspect-oriented programming with AspectJ

In one of the courses I took this session I was introduced to aspect-oriented programming. For those who are not familiar with it, an aspect can be used to implement a concern that is crosscutting among different components.

There are a few such concerns that are commonly affected by crosscutting, namely: authentication, persistence, logging and contract checking.

It is argued that with object-oriented programming, even after proper refactoring, it is not always possible to map a requirement to a single component. When a requirement is implemented by more than one component, scattering occurs. AOP allows you to localize the scattered requirement into an aspect.

AspectJ is an extension to the Java language that adds support to AOP. An aspect in AspectJ is composed of pointcuts and advices. A pointcut defines the condition that needs to be met in order for the logic in an advice to be executed. A pointcut could be, for instance, the execution of a method in a particular class.

How AspectJ can be useful

Let’s look at an example. Say we want to log when horses drink water and when cows eat grass. Assume we have a class Logger with a static method log(). Here’s what the implementation could look like:

public class Horse {
	private int consumedWaterInLitres;

	public void drink() {
		consumedWaterInLitres++;
		Logger.log("A horse is drinking water.");
	}
}

public class Cow {
	private int consumedGrassInGrams;

	public void eat() {
		consumedGrassInGrams++;
		Logger.log("A cow is eating grass.");
	}
}

The argument is that the concern of logging is now crosscut among the Horse and Cow components. In addition, it can be said that Horse.drink() and Cow.eat() are responsible for more core logic (eating and drinking) than they should have been. Let’s try to fix this problem with an aspect:

public aspect Logging {
	pointcut logHorseDrinking() : call(public void Horse.drink());
	pointcut logCowEating() : call(public void Cow.eat());

	void after() : logHorseDrinking() {
		Logger.log("A horse is drinking water.");
	}

	void after() : logCowEating() {
		Logger.log("A cow is eating grass.");
	}
}

Here we defined two pointcuts that capture calls to Horse.drink() and to Cow.eat(). We’ve attached these pointcuts to two advices that will run after these methods are executed. With the Logging aspect in place, we can now remove all calls to Logger.log() from Horse and Cow. Isn’t that great?

How AspectJ can be dangerous

Dog before DogAspect

Aspects can also add state, behaviour and inheritance to a component. Privileged aspects have access to all features in a system, including private ones. Does that raise a red flag? Let’s look at the class Dog below.

public class Dog {
}

It has no features—no attributes nor methods—and doesn’t extend from any class, right? Wrong:

public aspect DogAspect {
	declare parents: Dog extends Animal;
	private String Dog.ownersName = "Bobert";

	public String Dog.getOwnwersName() {
		return ownersName;
	}
}

Dog after DogAspect

The aspect above has completely changed the class Dog. It has made it an Animal, it has added an attribute ownersName and a getter for it. The worst part is that Dog is completely oblivious to the aspect. In fact, unless you as a developer look at all aspects on the system, you will never know about it either.

That is not completely true because some IDEs will provide a visual clue whenever a class is affected by an aspect. The AspectJ Developement Tools add-on for Eclipse (a great IDE by the way) is supposed to show a marker on the editor margin whenever a component is being advised by an aspect. I have the latest version installed (ADJT 1.6.4) but for some reason the marker is not showing up, unfortunately.

There are also other issues one might encounter when using AspectJ. It is not an easy task to document the impact aspects have on a system—UML has no support for aspects at this moment—how are you going to show that on a sequence diagram? Also, the debugging and tracing of execution of a class that is being advised by an aspect can get pretty tricky.

In conclusion

I believe that the application of AOP could indeed improve the quality of a system through the localization of crosscutting concerns. However, its Java implementation—AspectJ—provides a level of control that is too risky to be used in industrial medium- to large-scale projects. Its supporting technologies and documenting tools have not yet reached the desired maturity level.

  • Achim Demelt

    Good summary, and I completely share your concerns. I really love the AO paradigm, but AspectJ is simply too powerful. The Java programming language is too low-level for successful AO application.

    I prefer applying aspects on a higher level of abstraction (e.g. models). Under no circumstances must aspects be allowed to break the encapsulation of classes or components.

    • http://saulosilva.com Saulo

      I agree–you can really break encapsulation with AspectJ if you are not careful.

  • http://fogus.me fogus

    …an aspect can be used to implement a concern that is crosscutting among different components.

    I was a little worried when I read this as it is one of those self-licking lollipop kind of definitions that only makes sense if you already know what AOP means. However, you pull it together after that and explain the essentials nicely.
    -m

    • http://saulosilva.com Saulo

      I see what you mean. As I wanted to get into a simple practical example quickly, I might have provided a rather unsatisfactory definition (for a layman, at least).

      Thanks much for reading the article and thanks for your comments.