Summary
In a recent blog post, Alistair Israel presents an example of writing two simple Java annnotations to specify required fields of a bean. He then shows how to use those custom annotations with Spring's validation framework.
Advertisement
While many more developers use an existing API's annotations than create custom annotations, custom annotations are both easy to define in Java 5, and can also be very useful in keeping your code clean.
The simplest type of annotations are marker annotations, allowing you to mark a class, a method, or a field, as being somehow special in your application. One use-case for such annotations is validation: By designating a bean property as @required, for instance, a framework can perform automatic checks at runtime to ensure that a value is assigned to that bean property.
In a recent blog post, Spring Validation with Java Annotations, Alistair Israel shows two simple validation-related custom annotations, and demonstrates how those custom annotations can be used within a Spring application to validate input.
His first annotation marks a class as validatable:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validatable {
}
The second annotation, in turn, marks a property accessor as required:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Required {
}
The pair allows a class to be annotated thus:
@Validatable
public class LoginForm {
@Required
public String getUsername() {
return this.username;
}
@Required
public String getUsername() {
return this.username;
}
}
A validation implementation can thereafter inspect a class and its property accessors to see if a given property is required:
public final boolean supports(final Class clazz) {
return clazz.isAnnotationPresent (Validatable.class);
}
Once a class is deemed validatable, that class' property accessors can be inspected to determine the need to perform property validation:
final PropertyDescriptor[] propertyDescriptors
= BeanUtils.getPropertyDescriptors(obj.getClass());
for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
Method method = PropertyDescriptor.getReadMethod();
if (method != null && method.isAnnotationPresent(Required.class)) {
}
}
These examples show that defining custom annotations can add useful metadata to a class or method without cluttering up the code. The annotations can be present at runtime (by specifying @Retention(RetentionPolicy.RUNTIME) for the annotation), and annotation processing can be delegated to a component interested in that metadata, such as a validator.
What are some of your favorite use-cases for custom annotations?
The Spring JMX annotations are definitely high on my most favorite custom annotations list. (And I'm glad to see that the JMX JSR is starting to adopt the annotation-based way of working.)