AspectJ in Practice: Reap the Benefits of Modularity

spect-oriented programming (AOP), a contemporary programming technology with a large number of supporters, is in essence an improved version of object-oriented (OO) programming technology that enables program objects to be classified and built into hierarchical structures. Its concepts are currently utilized in complex programs that process financial transactions.

Fundamentally, AOP assumes that any complex system has some inherent crosscutting issues and concerns, which traditional programming methodologies do not address well. Aspects are new programming constructs that cross-cut the modularity of traditional programming constructs in carefully-designed and principled ways. For example, a single aspect can affect the implementation of a number of methods in a number of classes, enabling aspects to capture the cross-modular structure of these kinds of concerns in a clean way. This way AOP keeps these concerns from getting tangled by isolating crosscutting aspects into individual blocks.

AspectJ, a general-purpose, aspect-oriented extension to the Java language, is a collection of tools for AOP. Originally developed by professionals from Xerox’s Palo Alto Research Center to grow the technology and community in 2002, it has since moved to the Eclipse Project. AspectJ contains expansions and tools that enable Java developers to better manage the problems in large program systems and to reap the benefits of modularity. AspectJ provides clean modularization of crosscutting concerns, such as:

  • Error checking and handling
  • Synchronization
  • Context-sensitive behavior
  • Performance optimizations
  • Monitoring and logging
  • Debugging support
  • Multi-object protocols

This extension (which you can think of as a plug-in or addition) is not only very easy to learn and use, but since it’s developed on the Java platform, it also adheres to the “write once, run anywhere” rule. It can run with any Java program and on any Java-2-compatible platform. Consisting of a compiler, a debugger, a generator of documentation, and a structure browser, AspectJ can offer invaluable assistance with logging, debugging, or testing for almost all projects, making all these procedures as easy as 1-2-3. Developers can also establish further separation from their final software project releases by simply excluding AspectJ from the compilation process.

This article demonstrates how you can use AspectJ in your development processes. It includes a “Hello world” example that already has become very well known in the AspectJ development community. The article can serve as either an introduction or your first endeavor into the AOP world. For a deeper understanding of the topic, consult the official documentation and manuals.

Which situations require AspectJ, you ask. Imagine the following scenario: you’re a member of a development team facing a huge project that a number of clients are going to buy, but each client has a few requests for the project. One needs logging functions in 10,000 specific places within your code. Another requires some very specific logging functions only for critical (from his point of view) parts and situations. A third client requires added networking, localization, etc.

Of course, you could rebuild the project’s structure, adding new functions with new configurations, creating new class dependencies, and so on, but since the project is already in development, you are under time pressure (as usual). Maybe add “hardcoded” patches? Yes, but a “patched” project likely will get out of control very quickly. Besides, it also requires testing, bug fixing, etc. Doesn’t that all sound like a real headache? Not with AspectJ. You can create aspects, which will do everything necessary.

Aspects are the essence of AspectJ. In general, an aspect is a modular unit that crosscuts the structure of other modular units. It exists in either design or implementation:

  • A design aspect is a modular unit of the design that crosscuts the structure of other parts of the design.
  • A code aspect is a modular unit of the program that crosscuts other modular units of the code.

This is a very general definition that doesn’t address OO, but suites the introductory purposes of this article. Aspects can have type, extend classes and other aspects, and be either abstract or concrete. They do not have constructors or finalizers, cannot be created with the new operator, and cannot be used interchangeably with classes. For more detailed info, consult the official documentation. However, here’s a brief listing of some of the things you can do with aspects:

  • Place code before or after a method call
  • Change method arguments
  • Track method calls using regular expressions
  • Change class hierarchies
  • Control the treatment of exceptions

Getting back to your project, even if you’ve never worked with AspectJ, you can easily recognize the advantages it would offer:

  • You can place additional code around method calls to provide logging.
  • To separate these logging, localization, or networking functions (it doesnt really matter for which function type you use your aspects) among your customers, you can track your methods with regular expressions, which AspectJ uses.
  • And the main advantage: none of these features will require any code updates. You can just create new aspects and recompile the project.

Install AspectJ
Since seeing a product work is better than just reading about it, download the most recent version of AspectJ. Once it’s downloaded, installation is pretty easy (assuming you already have the Java 2 SDK installed). Just execute the following command:

java jar downloaded_filename.jar

This will run an installer, which will help you complete the installation. After that, you need to correctly set the path names mentioned on the last step of installation. You are then ready to work with AspectJ in the “big project” example to follow.

Look at the following code for your big project:

1:				// Our Java example  TestClass.java2:				public class TestClass {3:4:					public static void method1() {5:						System.out.println("Hello World!");6:					}7:8:					public static void method2() {9:						System.out.println("Really Hello!");10:					}11:12:					public static void say(String x) {13:						System.out.println(x);14:					}15:16:					public static void main(String[] args) {17:						method1();18:						method2();19:						say("I can talk!");20:					}21:				}

This code intentionally is easy, beginner-level Java to make understanding the technology easier. You can create more complex code after you’ve mastered aspects. Lines 4-6 and 8-10 define the class methods, which perform the only job: printing the well-known “Hello World” prompt. Lines 12-14 contain the other method, which says whatever you “ask” it to say. And last but not least, the main() function of the class calls all the methods.

Compile and run this example:

javac TestClass.javajava TestClass

The output is the following:

Hello World! Really Hello!I can talk!

Nothing unexpected, I presume. Now, create the AspectJ code in Listing 1.

Strange code, isn’t it? It looks pretty hard at first glance. But don’t worry, it’s not. Line 2 creates the aspect TestMe. Line 4 defines pointcut (it picks out certain join points in the program flow) for all public methods of class TestClass that are without arguments. Line 5 defines pointcut for all public methods of class TestClass that accept arguments of String type. Lines 7-10 define what will be executed before all public methods of class TestClass that accept one String type argument (defined in second pointcut). Lines 12-15 define what will be done after the previously mentioned methods. Lines 17-19 and 21-23 share the same definitions as the first pointcut methods. Notice that lines 9, 14, 18, and 22 use the following call:

thisJointPointStaticPart.getSignature().getName()

The result is the name of the method before or after which you are functioning. Argument a in lines 7 and 12 holds the value of the argument that passed to the methods as a String type argument.

Compile AspectJ
Compilation is easy, too. Just execute the following:

ajc TestMe.aj TestClass.javajava TestClass

(Note: You can list as many .java files as you need after TestClass.java; all of them will use the aspects created in TestMe.aj)

The output will be the following:

 -- TestClass.method1 start --Hello World! -- TestClass.method1 stop -- -- TestClass.method2 start --Really Hello! -- TestClass.method2 stop -- -- TestClass.say(I can talk!) start --I can talk! -- TestClass.say(I can talk!) stop --

Now do you see how useful AspectJ can be? Even this simple example shows the power of this technology. You didn’t change a single line of your main class code, but you already have a perfect solution for logging or testing!

Another AspectJ Benefit
Another interesting functionality of aspect is very useful when you need localization. To see it, just comment lines 7-15 (otherwise it creates a circular dependency at method-call) and add the following code after them:

void around(String a): methodCallArg(a) {				proceed("it is not '" + a + "' anymore!");			}

Compile and run it the same way you did before. Look at the output. If you completed everything properly, you’ll see that the say() method (which previously received the String “I can talk!”) receives and outputs the next String: “it is not I can talk! anymore!” A real argument passed to the previously mentioned code, and only after being changed, did it pass directly to the say() method. This could serve as an interesting scheme with localization. For example, you can check some constants about which language you are using once, and then provide output in that exact language.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Related Posts