Code Documentation with Java Annotations

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 the Action 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.

Mastodon