ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Aspect-Oriented Annotations Aspect-Oriented Annotations

by Bill Burke, coauthor of Enterprise JavaBeans, 4th Edition
03/02/2005

Annotations are one of the new language features in J2SE 5.0, and allow you to attach metadata onto any Java construct. Meanwhile, Aspect-Oriented Programming (AOP) is a fairly new technology that makes it easier for you to encapsulate behavior that is usually messier, harder, or impossible to do with regular object-oriented (OO) techniques. Together, they make a new powerful combination that gives framework developers a more expressive way of providing their APIs. This article dives into combining these technologies using the JBoss AOP framework in various coding examples to show how you can use this combination to actually extend the Java language.

Annotation Overview

First let's give a brief overview of the two technologies. Annotations are new to JDK 5.0 and are defined in detail in the JSR-175 specification. They allow you to define metadata in a typesafe way and apply it to a class, method, constructor, field, or parameter. For those of you familiar with XDoclet, annotations will be very intuitive to you in that you are used to declaring tags to generate code. The main difference between the two is that annotations are a typed part of the Java language, while XDoclet tags can be mistyped and are harder to create. I like to work with examples, so let's show a simple one.

To define an annotation, all you need to do is declare a special kind of Java interface.

Orange.java

package org.jboss.colors;

public @interface Orange {}

After defining this interface, you can use it to give more description to your Java elements.

Foo.java

package org.jboss.examples;

public class Foo
{
   @Orange void someMethod();

   @Orange private int someField;
}

So what can use use annotations for? Some people envision using annotations for code generation and a replacement for XDoclet. Others, like the J2EE and EJB 3.0 expert groups, see it as a replacement for deployment descriptors. This article talks about how annotations can be used with AOP.

AOP Overview

There are many articles and books that explain what AOP actually is, such as Graham O'Regan's ONJava article "Introduction to Aspect-Oriented Programming." I'll give a quick overview in this article, but I encourage you to do more research online.

AOP is about the clean separation and encapsulation of cross-cutting concerns. Sounds academic, I know, but bear with me for a minute. A cross-cutting concern is the code sprinkled throughout your codebase, code that has structure, but cannot be organized or declared using traditional OO techniques. AOP is best explained by example, so let's walk through one to more clearly understand what AOP actually is.

Let's say you wanted to add code to an application to measure the amount of time it would take to invoke a particular Java method. The code could look something like this:

public class BankAccount
{
  public void withdraw(double amount)
  {
    long startTime = System.currentTimeMillis();
    try
    {
      // Actual method body...
    }
    finally
    {
      long endTime = System.currentTimeMillis() - startTime;
      System.out.println("withdraw took: " + endTime);
    }
  }
}

While this code works just fine, there are a few problems with this approach:

  1. It's extremely difficult to turn metrics on and off, as you have to manually add the code in the try/finally block to each and every method or constructor you want to benchmark.
  2. The profiling code really doesn't belong sprinkled throughout your application code. It makes your code bloated and harder to read, as you have to enclose the timings within a try/finally block.
  3. If you wanted to expand this functionality to include a method or failure count, or even to register these statistics to a more sophisticated reporting mechanism, you'd have to modify a lot of different files (again).

Metrics present a perfect, tiny, small example of what a cross-cutting concern is. JBoss AOP provides a simple way of encapsulating and applying such a concern in an implicit way so that something like metrics code does not pollute your codebase. Let's dive into JBoss AOP a bit to see how you can do this.

To encapsulate metrics functionality using JBoss AOP, you first need to define an aspect that specifies the metrics behavior.

public class Metrics
{
   public Object profile(MethodInvocation invocation) throws Throwable
   {
      long startTime = System.currentTimeMillis();
      try
      {
         return invocation.invokeNext();
      }
      finally
      {
         long endTime = System.currentTimeMillis() - startTime;
         java.lang.reflect.Method m = invocation.getMethod();
         System.out.println("method " + m.toString() +
                            " time: " + endTime + "ms");
      }  
   }
}

An aspect is just a plain Java class that has methods in it that define the behavior you want to attach to your object model. The signature of these methods must return a java.lang.Object and must have one (and only one) argument of a JBoss AOP invocation object, which is used to encapsulate the method, constructor, or field invocation. The method name can be anything you want and is referenced when you actually bind the aspect to a piece of your code.

The next thing to do is to actually apply the aspect to the points in your program where you want it to profile a method's execution. Most AOP frameworks provide a pointcut expression language where you can define where you want certain aspect behavior to be attached. Here's how to do this in JBoss AOP.

jboss-aop.xml

<aop>
   <aspect class="Metrics"/>

   <bind pointcut="execution(public void BankAccount->withdraw(double amount))">
      <advice name="profile" aspect="Metrics"/>
   </bind>
</aop>

With the definition of the aspect in Metrics.java and the pointcut definition within jboss-aop.xml, the metrics code is now applied implicitly and transparently to the BankAccount.withdraw() method and can easily be removed when the profiling code is no longer needed by the application.

For more information on JBoss AOP, check out the tutorial that comes with the distribution. It has about 20 example programs that walk you through how to use the JBoss AOP framework.

Annotations and AOP

Phew! Now that we've been through the overviews, let's start diving into the meat of the article. I'm going to throw a lot of examples at you again, as it's the best way I know of to teach a new concept.

As I said before, annotations plus AOP almost give you the ability to extend the Java language. Annotations provide the mechanism for declaring new, compilable, typesafe syntax. AOP provides the mechanism to encapsulate and apply new behavior to a syntactical expression.

Method Annotations and AOP

Let's take a look at how you can use method annotations with AOP. Using annotations and AOP together and applying this to a method is very analogous to using Java's synchronized keyword with a method. When you tag a method as synchronized, you are telling the JVM that you want that method to behave in a special way when it is invoked. Annotations allow you to define new keywords that you want to have trigger your own special custom behavior. AOP gives you the ability to encapsulate this behavior and weave it into the execution of the method. Again, this concept is best described in an example.

Let's say we want to add a new syntax that will allow us to fire void methods in the background, in another thread, if they are tagged as @Oneway. Using this new syntax would look like this:

import org.jboss.aspects.Oneway;

public class Foo
{
   @Oneway public static void someMethod() {...}

   public static void main(String[] args) 
   {  
      someMethod(); // executes in background
   }
}

When someMethod() is invoked within main, it will run asynchronously so that the code in main is free to do other tasks in parallel.

To implement this functionality, the first thing that must be done is to define the new Java syntax for our @Oneway tag within an annotation.

Oneway.java

package org.jboss.aspects;

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

@Target({ElementType.METHOD})
public @interface Oneway {}

Simple enough. The @Target tag allows you to narrow down where the annotation is allowed to be applied. In this case, our @Oneway annotation can only be applied to a method. Remember, this is all pure 100 percent Java that is available in J2SE 5.0.

The next thing we have to do is to define an aspect class that will encapsulate our @Oneway behavior.

OnewayAspect.java

package org.jboss.aspects;

public OnewayAspect
{
   private static class Task implements Runnable
   {
      private MethodInvocation invocation;

      public Task(MethodInvocation invocation)
      {
        this.invocation = invocation;
      }
      public void run()
      {
        try { invocation.invokeNext(); }
        catch (Throwable ignore) { }
      }
   }
   

   public Object oneway(MethodInvocation invocation) throws Throwable
   {
      MethodInvocation copy = invocation.copy();
      Thread t = new Thread(new Task(copy));
      t.setDaemon(false);
      t.start();
      return null;
   }
}

The aspect is simple enough. The oneway() method copies the invocation, creates a thread, fires off the complete invocation in the background, and returns. We could imagine a more sophisticated example using some of the new Executors within the J2SE 5.0 java.util.concurrent package, but hopefully this code illustrates how you could build on this example to implement more complete implementations.

The last thing that must be done is to specify the pointcut expression that will trigger the application of the OnewayAspect when the @Oneway annotation is declared on a method.

jboss-aop.xml

<aop>
   <aspect class="org.jboss.aspects.OnewayAspect"/>

   <bind pointcut="execution(void *->@org.jboss.Oneway(..))">
      <advice name="oneway"
              aspect="org.jboss.aspects.OnewayAspect"/>
   </bind>
</aop>

The pointcut expression states that any void method that is tagged as @Oneway should have the OnewayAspect.oneway() method executed before it itself executes. With the annotation, aspect, and pointcut expression now defined, the @Oneway syntax is now usable in your application. A simple, clean, easy way of extending the Java language!

Field Annotations and AOP

Let's look at how you could use field annotations and AOP. Using annotations and AOP, you can can actually change how a field is stored by an object or as a static member of a class. What we want to accomplish in this example is that when you tag a field (static or member) as @ThreadBased, its value will behave as though it were stored in a java.lang.ThreadLocal. Sure, you could use a ThreadLocal variable directly, but the problem with ThreadLocal is that it is untyped and you have to use "verbose" (okay, they're not that verbose) get() and set() methods. So what we'll do here is create a typed ThreadLocal field. Basically, we'll create a new Java field type called the @Threadbased variable.

Using this new type would look like this:

import org.jboss.aspects.Threadbased;

public class Foo
{
   @Threadbased private int counter;
}

To implement this functionality, we must first define the annotation.

Threadbased.java

package org.jboss.aspects;

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

@Target({ElementType.FIELD})
public @interface Threadbased {}

Simple enough. The @Target tag allows you to narrow down where the annotation is allowed to be applied. In this case, our @Threadbased annotation can only be applied to fields.

The next thing to do is to define the aspect that will encapsulate our ThreadLocal behavior.

ThreadbasedAspect.java

package org.jboss.aspects;

import org.jboss.aop.joinpoint.*;
import java.lang.reflect.Field;

public class ThreadbasedAspect
{
   private ThreadLocal threadbased = new ThreadLocal();

   public Object access(FieldReadInvocation invocation)
       throws Throwable
   {
      // just in case we have a primitive,
      // we can't return null
      if (threadbased.get() == null)
          return invocation.invokeNext();
      return threadbased.get();
   }

   public Object access(FieldWriteInvocation invocation)
       throws Throwable
   {
      threadbased.set(invocation.getValue());
      return null;
   }
}

ThreadbasedAspect encapsulates the access to a Java field. It has a dedicated ThreadLocal variable within it to track threadlocal changes to a particular field. It also has separate access() methods that are invoked depending upon whether a get or set of the field is called. These methods delegate to the ThreadLocal to obtain the current value of the field.

Finally, we must define a pointcut expression that will trigger the application of the ThreadbasedAspect when the @Threadbased annotation is specified on a particular field.

jboss-aop.xml

<aop>
   <aspect class="org.jboss.aspects.ThreadbasedAspect" 
           scope="PER_JOINPOINT"/>
   <bind pointcut="field(* *->@org.jboss.aspects.Threadbased)">
      <advice name="access"
              aspect="org.jboss.aspects.ThreadbasedAspect"/>
   </bind>
</aop>

Just in case we have multiple @Threadbased variables defined in one class, we want an instance of ThreadbasedAspect to be allocated per field for static fields. For member fields, we want an instance of ThreadbasedAspect to be allocated per field, per object instance. To facilitate this behavior, the aspect definition scopes the instance of when and where the aspect class will be allocated by setting it to PER_JOINPOINT. If we didn't do this scoping, JBoss AOP would only allocate one instance of ThreadbasedAspect and different fields would be sharing the same instance of the ThreadLocal -- something that we don't want.

Well that's it. A clean, easy way of extending Java to specify a new special type. Note: This particular aspect comes bundled with JBoss AOP.

Dependency Injection

Another interesting place where field annotations and AOP can be used is with dependency injection. Dependency injection is about objects declaring what information, configuration, or service references they need, and having the runtime automagically inject those dependencies rather than having your code do explicit lookups on a registry service. In J2EE-land, getting access to a javax.transaction.TransactionManager service is not standardized and is actually different per vendor implementation. Many framework developers need to use the TransactionManager to implement custom transactional services. The use of AOP with field annotations is a great way to provide this dependency injection and to abstract away the details of how a TransactionManager is referenced by components that need it. Let's define an aspect that will inject a reference to a TransactionManager into the value of a field.

First, we must again define our annotation.

Inject.java

package org.jboss.aspects;

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

@Target({ElementType.FIELD})
public @interface Inject {}

Next we will define the aspect class that will encapsulate the resolving of the TransactionManager. This aspect will be specific to the JBoss application server, but you could define different implementations per vendor.

InjectTMAspect.java

package org.jboss.aspects;

import org.jboss.aop.joinpoint.*;
import java.lang.reflect.Field;
import javax.transaction.TransactionManager;
import org.jboss.tm.TxManager;

public InjectTMAspect
{
   private TransactionManager tm = TxManager.getInstance();

   public Object access(FieldReadInvocation invocation)
       throws Throwable 
   {
      return tm;
   }

   public Object access(FieldWriteInvocation invocation)
       throws Throwable 
   {
      throw new RuntimeException(
          "Setting an @Injected variable is illegal");
   }
}

Finally, we have to define the XML binding that will trigger the application of the InjectTMAspect when the @Inject tag is applied to a field. The pointcut expression basically states that for any field of type TransactionManager and tagged as @Inject, apply the InjectTMAspect.

<aop>
  <aspect class="org.jboss.aspects.InjectTMAspect"/>

  <bind pointcut="field(javax.transaction.TransactionManager *->@org.jboss.aspects.Inject)">
     <advice name="access"
             aspect="org.jboss.aspects.InjectTMAspect"/>
  </bind>
</aop>

Now that the annotation, aspect class, and XML binding have been defined, we can use it within our code.

import javax.transaction.TransactionManager;
import org.jboss.aspects.Inject;

public class MyTransactionalCache
{
   @Inject private TransactionManager tm;
...
}

More Pre-Packaged Examples

JBoss AOP is not just about an AOP framework. It also has a rich library of aspects that you can use directly within your applications. Within this library is a set of annotated aspects that are a bit more complex than the examples we've shown in this article. Some of these aspects include asynchronous invocations, transaction demarcation, transactional locking, and role-based security. Let's briefly walk through them to give you an even better idea on how annotations and AOP can work together.

Asynchronous Aspect

The JBoss AOP asynchronous aspect allows you to define any method as asynchronous so that it can be fired off in the background. It is a bit different from our @Oneway example, in that it uses the Executor facilities in the Oswego concurrent package, as well as providing a way to receive responses back asynchronously for those methods that have a return type. To use this aspect, you just tag a method as @Asynchronous.

public Foo 
{
   @Asynchronous public int someMethod(int someArg) {...}
}

The application of the @Asynchronous tag does a few things. As in the @Oneway example in this article, it applies an aspect that runs the method in the background. Also, with the @Asynchronous tag, you are not limited to void methods and may interact with methods that actually return a value. When the @Asynchronous tag is applied, it forces the Foo class to implement the AsynchronousFacade interface. In AOP-land, this is called an interface introduction. The AsynchronousFacade interface allows you to poll for a response, or wait for a response with a timeout. This is best explained with an example.

Foo foo = new Foo();

someMethod(555); // executes in background

AsynchronousFacade facade = (AsynchronousFacade)foo;
AsynchronousResponse response = facde.waitForResponse();

System.out.println(response.getReturnValue());

You can fire off multiple invocations to multiple different methods of multiple different objects, and asynchronously accumulate their responses.

Transaction Locking

Sometimes it may be useful to synchronize an object or class for the duration of a J2EE transaction rather than for just the duration of a method call, constructor invocation, or synchronized block. For this type of transactional synchronization/locking, JBoss AOP has invented the @TxSynchronized keyword. You can use @TxSynchronized on any member or static method, as well as on a constructor.

import org.jboss.aspects.txlock.TxSynchronized;

public FooBar
{
   @TxSynchronized public FooBar() {}

   @TxSynchronized static void staticMethod() {}

   @TxSynchronized public memberMethod() {}
}

If a constructor or static method that is tagged as @TxSynchronized is invoked, the lock monitor for the class will be held for the duration of the transaction. If a member method tagged as @TxSynchronized is called, the lock monitor for the particular object instance will be held until the current transaction commits or rolls back. The aspect that controls this behavior also will do deadlock detection and will throw a RuntimeException if deadlock is encountered.

J2EE a la Carte: Transaction Demarcation

EJB 3.0 has defined some annotations to do transaction demarcation. JBoss AOP builds on this so that you can apply transaction demarcation to any method (static or member) and any constructor of any Java class by specifying an annotation.

import org.jboss.aspects.tx.*;

public class Foo
{
   @Tx(TxType.REQUIRED) public Foo {}

   @Tx(TxType.REQUIRESNEW) public static createFoo() {
      return new Foo();
   }
}

J2EE a la Carte: Role-Based Security

EJB 3.0 has also defined some annotations to do role-based security. JBoss AOP builds on this so that you can apply role-based security to any field or method (static or member) as well as any constructor.

import org.jboss.aspects.security.*;

@SecurityDomain("LDAP Repository")
public class Foo
{
   @Permissions({"admin"}) public Foo() {}

   @Permissions({"developer"}) public static int status;

   @Permissions({"anybody"}) public static void doSomething() {...}

}

EJB Evolution

As AOP matures along with the EJB specification, what I really hope happens is that the annotations defined in the EJB specification will be usable in any context as new adjectives to the Java language, rather than their limited constricted use within session beans. Imagine a truly stateless bean being just a set of static methods on a plain Java class.

public MySessionBean
{
   @Tx(TxType.REQUIRED) public static doSomething() {...}
}

Anyways, this talk of AOP and EJB is probably for EJB 4.0.

Conclusion

Instead of limiting J2SE 5.0 annotations for use with code generation, annotations and AOP can be combined to give new power to framework developers. The combination allows developers to define new Java syntax that actually has behavior attached to it. Basically, the ability to extend the Java language in a typesafe way is within our grasp.

Bill Burke is a Fellow at the JBoss division of REd Hat Inc. A long time JBoss contributor and architect, his current project is RESTEasy, RESTful Web Services for Java.

Better, Faster, Lighter Java

Related Reading

Better, Faster, Lighter Java
By Justin Gehtland

Return to ONJava.com.

Copyright © 2009 O'Reilly Media, Inc.