Java Platform, Enterprise Edition

Java EE Journal

Subscribe to Java EE Journal: eMailAlertsEmail Alerts newslettersWeekly Newsletters
Get Java EE Journal: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


J2EE Journal Authors: Douglas Lyon, Stackify Blog, APM Blog, Sumith Kumar Puri, Javier Paniza

Related Topics: Java EE Journal, Java Developer Magazine

J2EE Journal: Article

Kicking the Tires on Java 5.0

Building an aspect-oriented framework based on annotations

I'm really jazzed about Java 5.0! We've been treated over the years to incremental improvements in JVM performance. JDK 1.2 brought us the collections framework as well as Swing, the thread context class loader, and improvements in RMI. JDK 1.3 and 1.4 continued in the same vain with logical improvements to libraries, JVM enhancements, and performance upgrades. Although this article doesn't intend to take trip down memory lane, it's important to understand that Java 5.0 brings a truly remarkable and rich set of new tools to our programming landscape as compared to other JDK releases.

This article will survey some of Java 5.0's new features and put them into practice through example. We'll build up a lightweight aspect-oriented system based on annotations to showcase what's new in 5.0. Some of these features you may be familiar with, some you may not. I've attempted to mix the obvious with some of the obscure. We'll examine some of the new hooks that the JVM has exposed for class loading, which makes the once dreadful work of bytecode manipulation during class loading much easier. In the "obvious" column, we'll look at generics and how they enable us to write more robust and sane programs, especially when dealing with collections. Perhaps the most notable aspect of Java 5.0 that we'll examine is the annotation framework. Annotations allow developers to inject metadata into their applications. We'll use this feature to demark classes we want manipulated at load time. To put this all in context, we'll create a lightweight framework that will manipulate classes as they are being loaded to enable logging, security, BAM (business activity monitoring), or any number of other scenarios that have yet to be dreamed up (The source code for this article can be downloaded from http://jdj.sys-con.com.)

Annotations
Annotations are nothing new. In concept we've been injecting forms of metadata into our programs for years. If you've ever used XDoclet or EJBGEN to annotate a class in preparation for EJB deployment descriptor generation, you've used a form of annotation. Although these annotation methods are primarily manipulated during compilation, frameworks do exist that allow runtime access to annotations. Those that come to mind are the Jakarta Commons Attributes project and the metadata infrastructure in the Spring framework. One important thing to note from the Spring documentation regarding the use of Java 1.5 annotations versus metadata available in the Spring framework is the following:

"JSR-175 metadata is static. It is associated with a class at compile time, and cannot be changed in a deployed environment. There is a need for hierarchical metadata, providing the ability to override certain attribute values in deployment - for example, in an XML file."

For our purposes, however, the annotations suggested by JSR-175 and implemented in Java 5.0 will be sufficient.

Anatomy of an Annotation
Generally, annotations are thought of only as artifacts useful at compile time by tool vendors to do such things as generating deployment descriptors. This is what utilities such as XDoclet and EJBGEN do. The annotations are examined at compile time, used to generate output (in the case of EJB this maybe a deployment descriptor) and in a sense are then discarded thereafter as an artifact. Annotations in Java 1.5 can behave in a similar way, but they can also be retained past the compilation stage and accessed at runtime. The developer has three retention policies to choose from. They are:

  • RententionPolicy.CLASS: Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at runtime
  • RententionPolicy.RUNTIME: Annotations are to be recorded in the class file by the compiler and retained by the VM at runtime, so they can be read reflectively.
  • RententionPolicy.SOURCE: Annotations are to be discarded by the compiler.
To declare a new annotation type, the developer must specify a retention policy for his or her annotation, what the element type is and what attributes the annotation possesses. The developer can associate an annotation with a particular element Valid element types are:
  • ElementType.Constructor: Associates an annotation with a constructor.
  • ElementType.Field: Associates an annotation with a field.
  • ElementType.LocalVariable: Associates an annotation with a local variable.
  • ElementType.Method: Associates an annotation with a method.
  • ElementType.Package: Associates an annotation with a package.
  • ElementType.Parameter: Associates an annotation with a parameter.
  • ElementType.Type: Associates an annotation with a type.
Let's look at a typical annotation declaration.

package annotations;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})

public @interface BAMAnnotation
{
String insertionPoint();
String processBean();
}

What's notable here is that the annotation declaration is strikingly similar to an interface declaration and that the metadata for this annotation is defined in terms of an annotation! This particular annotation is used on a method and its values are accessible at runtime as dictated by the retention policy. The annotations require two attributes to be defined, "insertionPoint" and "processBean. To use this annotation in a class is pretty straightforward:


import annotations.*;

public class BizComponent
{

@BAMAnnotation(processBean="nullInjector",
insertionPoint="pre")
public void execute()
{
System.out.println("Executing"+
"some biz functionality");
}
}

Here we've associated our annotation with the "execute()" method of our "BizComponent" class. When we examine this class at runtime the values of "processBean" and "insertionPoint" will be "nullInjector and "pre" respectively.

Comments (3) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
slopzster 07/13/05 11:30:22 PM EDT

fantastic article, very thought provoking -- kudos. Can you comment on potential performance related issues in instrumented components that have high availability requirements?

Boris 06/29/05 11:45:06 AM EDT

I'm sorry, but I cann't find link to sources
of this cool article on the web pages.

Peter Braswell 06/24/05 01:03:39 PM EDT

This article will survey some of Java 5.0's new features and put them into practice through example. We'll build up a lightweight aspect-oriented system based on annotations to showcase what's new in 5.0. Some of these features you may be familiar with, some you may not. I've attempted to mix the obvious with some of the obscure. We'll examine some of the new hooks that the JVM has exposed for class loading, which makes the once dreadful work of bytecode manipulation during class loading much easier. In the "obvious" column, we'll look at generics and how they enable us to write more robust and sane programs, especially when dealing with collections. Perhaps the most notable aspect of Java 5.0 that we'll examine is the annotation framework. Annotations allow developers to inject metadata into their applications. We'll use this feature to demark classes we want manipulated at load time. To put this all in context, we'll create a lightweight framework that will manipulate classes as they are being loaded to enable logging, security, BAM (business activity monitoring), or any number of other scenarios that have yet to be dreamed up