ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Aspect-Oriented Annotations
Pages: 1, 2, 3

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.

Return to ONJava.com.