Tuesday, May 17, 2011

Annotation scanner with Spring

Spring framework, from version 2.5, can retrieve bean based on an annotation set such as @Service, @Repository. This mechanism uses an annotation scanner to retrieve the annotated classes through the classpath.

As Spring is easily extendable, it is possible to work with an annotation scanner dedicated to our own annotations.

The annotation

The annotation we want to use as a class marker, is not a psecial Spring define one. The only requirement is the retention must be runtime and the target must be at least TYPE.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation { }

The scanner

Firstly, we need to create an application context:

GenericApplicationContect applicationContext = new GenericApplicationContext();

And now, the annotation scanner:

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(applicationContext, false);

An annotation scanner needs an application context to store retrieved classes. The second parameter is used to avoid this scanner search after Spring framework defined annotations. Now, we must configure the scanner to retrieve only our annotation:

scanner.addIncludeFilter(new AnnotationTypeFilter(MyAnnotation.class));

Several filters are available to include or exclude classes from the search, such as RegexPatternTypeFilter.

To trigger the scanning, we must call scan method with a package list as string array:

scanner.scan(packageNames);

Now, just refresh the context and get the annotated instance:

applicationContext.refresh();
Map<String, Object> result = applicationContext.getBeansWithAnnotation(MyAnnotation.class);

The map key is the bean Spring id, and the value is an instance. By default, the id is the simple class name.