Code Documentation with Java Annotations
A few years back, I took over a Java software project that had been written years before. The application was originally written as a generic platform that had later been refactored into a specific product. As such, there was a lot of code in the project that had been written for the original platform, but was not used in the product I was taking over. To make matters worse, I also found that:
- The application used reflection in a handful of places, so I couldn't trust when IntelliJ told me that code was unused.
- The in-code documentation was pretty slim and unhelpful.
- The application used the Struts2 MVC framework, but the original developers implemented the
Action
interface for controllers and service-layer classes. This made it impossible to tell at first glance if a class was a controller or a service class. - Background jobs, which were invoked by the Quartz Scheduler, also implemented the Struts2
Action
interface.
As I began documenting the code, I needed to be able to make consistent notes. Rather than just leaving comments like "not really an action" or "this is a quartz job" in a bunch of classes, I decided to use annotations to record my notes. It worked something like this:
package com.someproject.source.metadata.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates that the annotated type is not a Struts2 action class. The project
* code contains interfaces and classes which have the Action keyword
* as part of their name and which extend the Action and ActionSupport types
* for classes which are not really actions (e.g., not mapped in the struts.xml).
*
* <p>These classes have a different purpose and exist at a different level in the
* MVC paradigm. As such, they should carry a different naming convention (e.g.,
* Task instead of Action) and should not extend the Action or ActionSupport
* classes. This would provide a more clear understanding of their purpose.
*
* @author Steven Benitez
*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface NotAnAction {
}
This approach offered a number of benefits. First, searching for classes that had a specific annotation was much easier than searching for a comment string which might not always be consistent. Second, I could document the annotation itself (as seen above), going into more detail about what the annotation represented.
I created several annotations, including:
@NotAnAction
for classes that implemented theAction
interface but were not controllers@NotUsed
for classes that appeared to be unused but might be called reflectively@QuartzJob
for classes that were invoked via the Quartz Scheduler
I found this approach to work well, and would employ it again.