a little madness

A man needs a little madness, or else he never dares cut the rope and be free -Nikos Kazantzakis

Zutubi

Annotation Patterns: The Meta Squared Pattern

Over the past couple of weeks, I have been working on adding plugin support to pulse. One of the primary requirements is to provide as much functionality out of the box as possible, allowing plugin writers to focus on the features, not support code. For example, if a plugin requires configuration, then the plugin developer should define what input is required, what validation rules should be applied, but not have to worry about the details of rendering and validating a web form. But more on that later.

Whilst doing some research into what was already being done, I came across an approach to using annotations that I have since found very useful. For reference, the project was the excellent trails project from Brian Topping.

The approach centres around defining the annotation, and annotating the annotation with a reference to its handler.

@Constraint(RequiredValidator.class)
public @interface Required
{
}

In the code example above, you can see that the Required annotation has a reference to the RequiredValidator, its handler.

By adding a simple annotation processor that searches for annotated annotations and executes the handler, you have the basis of a very flexible meta data processing facility. The core of the flexibility here is that a custom annotation does not need to be registered with the processor. The information normally conveyed by the registration process is embedded in the annotation.

Lets see how this works in practice by applying it to the validation domain by implementing custom Name validation rules.

Firstly, the validator:

public class NameValidator extends RegexValidator
{
  public NameValidator()
  {
    setPattern("[a-zA-Z0-9][-a-zA-Z0-9_. ]*");
  }
}

Then the annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(NameValidator.class)
public @interface Name
{
}

And finally, we apply it to our business object:

@Name
  public void setMyName(String name)
  {
    this.name = name;
  }

The core of the annotation processor would look like:

private void processConstraints(Method method, Object obj)
{
  for (Annotation annotation : method.getAnnotations())
  {
    Constraint constraint = annotation.annotationType().
                     getAnnotation(Constraint.class);
    if (constraint != null)
    {
      Class constraintHandlerClass = constraint.value()
      // we now have the handler, now we just need to
      // apply it to the instance being validated.
    }
  }
}

private boolean isConstraint(Annotation annotation)
{
  return annotation.annotationType().
           getAnnotation(Constraint.class) != null;
}

We are also applying this same technique to the plugin frameworks’ automatic form generation, and anywhere else where we want plugin authors to be able to use annotations to customise the default behaviour of the framework.

Liked this post? Share it!

2 Responses to “Annotation Patterns: The Meta Squared Pattern”

  1. December 13th, 2006 at 3:34 am

    Elmar Juergens says:

    Hi,

    I am currently trying to better understand annotations and their meaningful use. I really like this post, now I want more: Are you aware of more material on patterns of annotation use?

    Thanks a lot,
    Elmar

  2. December 14th, 2006 at 3:23 am

    Daniel says:

    Hi Elmar,

    I have not found much material dealing with this topic specifically. If you are interested in looking at the practical usages of annotations, a good place to start would be taking a look at the trails project. Whilst it does contain a lot of distractions, it does make heavy use of annotations provide a good real world working example.

    Sorry that I could not be of more help.

    -Daniel

Leave a Reply