An introductory guide to annotations and annotation processors
Tags: java, annotation, annotationprocessor
Published: 2020-04-26 17:16:30

In Java, annotations and annotation processors are surrounded by a shroud of mystery for most. They seem like a subject reserved for "experts"". On top of that, I believe there’s also some <abbr title="Fear Confusion and Doubt">FUD</abbr> around them. This post aims to dig into the subject, in the most neutral way possible. This way, everybody can take enlightened decisions based on facts, not by listening to people full of misconceptions or hidden agendas.

Annotations are available since Java version 5, codenamed <em>Tiger</em>, and released in 2004.

<blockquote>In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code. Classes, methods, variables, parameters and Java packages may be annotated.
— Wikipedia<br>
<cite>https://en.wikipedia.org/wiki/Java_annotation</cite>
</blockquote>

The most simple annotation looks like the following:

```java
@MyAnnotation public class Foo {}
```

Because of the lack of annotations, previous Java versions had to approach some features in oblique ways.

<strong>Replacement of <strong>marker interfaces</strong>

Since Java’s inception, there has been a need to mark a class, or a hierarchy of classes. Before Java 5, this has been done through <em>interfaces with no methods</em>. <code>Serializable</code> and <code>Cloneable</code> are two examples of such interfaces.

![List of marker interfaces in Java](https://dev-to-uploads.s3.amazonaws.com/i/scrpdj78lm81p8ths97d.png)

This kind of interface obviously is unlike any other: they don’t define any contract between themselves and their implementing classes. Hence, they have earned the name of marker interfaces.

People new to Java will in general ask questions related to that approach. The reason for that is because it’s a trick. Annotations remove the need for that trick, and keep the contract role of interfaces.

```java
public class Foo implements MarkerInterface {} // 1

@MyAnnotation
public class Foo {}                            // 2
```

1. Marker interface
2. Annotation equivalent to the marker inteface</dd>

<strong>Better metadata management</strong>

Deprecation is the process of flagging an API as obsolete. This way, users are informed about the change, can decide to stop using the API, and the latter may be removed with less impact in future versions. Prior to Java 5, deprecation was set in the JavaDocs:

```java
/**
 * Blah blah JavaDoc.
 *
 * @deprecated As of JDK version 1.1,
 */
public class DeprecatedApi {}
```

Obviously, this is a very fragile approach: the only way to leverage it is via the <code>javadoc</code> tool. The standard JavaDocs has a <a href="https://docs.oracle.com/javase/9/docs/api/deprecated-list.html" target="_blank" rel="noopener">section dedicated to such deprecated APIs</a>. Alternatively, the <code>javadoc</code> tool can be configured via a custom <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/javadoc/doclet/overview.html" target="_blank" rel="noopener">doclet</a>, to process Javadoc metadata (including but not limited to <code>@deprecated</code>) in any desired way.

With Java 5, deprecation is flagged with the provided <code>@Deprecated</code> annotation:

```java
/**
 * Blah blah JavaDoc.
 */
@Deprecated
public class DeprecatedApi {}
```

_**NOTE:** Old deprecated APIs keep the old approach, so they use both metadata and annotation._

Additionally, since Java 9, @Deprecated allows two elements:

| Optional element | Modifier and type | Description                                                                        |
|------------------|-------------------|------------------------------------------------------------------------------------|
| forRemoval       | boolean           | Indicates whether the annotated element is subject to removal in a future version. |
| since            | String            | Returns the version in which the annotated element became deprecated.              |

```java
@Deprecated(since="1.2", forRemoval=true)
public abstract class IdentityScope extends Identity {}
```

# Creating an annotation

To create an annotation, one uses the <code>@interface</code> keyword:

```java
public @interface MyAnnotation {}
```

However, this is not enough, as such an annotation cannot be set anywhere. Annotations require two more pieces of information:

1. A **target**: this defines where the annotation can be set
2. A **retention**: this describes up to which step in the compilation process the annotation will be available

We will get into more detail later. As for now, we first need to understand how annotations work. While classes inherit code from their parent class(es), **annotations are composed**.

```java
@Target(ElementType.ANNOTATION_TYPE)     // 1
@interface Foo {}

@Target(ElementType.ANNOTATION_TYPE)     // 1
@interface Bar {}

@Foo
@Bar
@interface Baz {}                        // 2
```

1. This is the required <code>@Target</code>, it will be explained further down
2. Something annotated with <code>@Baz</code> is transitively annotated with both <code>@Foo</code> and <code>@Bar</code>

Here’s the source code of <code>@Target</code> and <code>@Retention</code>:

```java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {             // 1
    ElementType[] value();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {          // 2
    RetentionPolicy value();
}
```

1. The `@Target` annotations tells on which element the annotation can be set:
    * On a type e.g. a class or an interface
    * On another annotation
    * On a field
    * On a method
    * On a constructor
    * On a method parameter
    * On a local variable
    * On a module
    * etc.
2. The `@Retention` annotation defines up to which step in the compilation process the annotation will be available:
    * Only the source code
    * In the class file
    * At runtime

This is summed up in the following class diagram:

![java.lang.annotation package class diagram](https://dev-to-uploads.s3.amazonaws.com/i/oqx2im9r5vu4qqs0sjtv.png)

# Annotation parameters

Annotations can define <strong>parameters</strong>. Parameters allow to add some level of configuration at the time the annotation is used. A parameter accepts a <em>type</em> and an optional <em>default value</em>. If the value is not set when the annotation is defined, it needs to be when it is used.

Parameter types are limited to the following:

* Any primitive type _e.g._ `int`, `long`, etc.
* `String`
* `Class&lt;T&gt;`
* Any `enum` type
* Another annotation type
* Any array of the above

```java
@Target(ElementType.CLASS)
@interface Foo {
  int bar();
  Class<? extends Collection> baz() default List.class;
  String[] qux();
}

@Foo(bar = 1, qux = { "a", "b", "c" })
class MyClass {}
```

If there’s a _single parameter_ and it’s named `value`, its name can be omitted when set:

```java
@Target(ElementType.CLASS)
@interface Foo {
    int value();
}

@Foo(1)
class MyClass {}
```

# Handling annotations at runtime: reflection

Since its inception, Java has allowed _reflection_: reflection is the capacity to get information about the code at runtime. Here’s a sample:

```java
var session = request.getHttpSession();
var object = session.getAttribute("objet");       // 1  
var clazz = object.getClass();                    // 2  
var methods = clazz.getMethods();                 // 3  
for (var method : methods) {
    if (method.getParameterCount() == 0) {        // 4  
        method.invoke(foo);                       // 5  
    }
}
```

1. Get an object stored in the session
2. Get the runtime class of the object
3. Get all `public` methods available on the object
4. If the method has no parameter
5. Call the method

With annotations, the reflection API got relevant improvements:

![Reflection Java API class diagram](https://dev-to-uploads.s3.amazonaws.com/i/3ifk932lwnof420sx2xz.png)

With annotation, frameworks started to make use of them for different use-cases. Among them, configuration was one of the most used: for example, instead of (or more precisely in addition to) XML, the <a href="https://spring.io/" target="_blank" rel="noopener">Spring framework</a> added a configuration option based on annotations.

# Handling annotations at compile-time: annotation processors

For a long time, both users and providers were happy with runtime reflection access to annotations. Because it’s mainly focused on configuration, reflection occurs at startup time. In constrained environments, this is too much of a load for applications: the most well-known example of such an environment is the Android platform. One would want to have the fastest startup time there, and the startup-time reflection approach makes that slower.

An alternative to cope with that issue is to **process annotations at compile-time**. For that to happen, the compiler must be configured to use specific **annotation processors**. Those can have different outputs: simple files, generated code, etc. The tradeoff of that approach is that compilation takes a performance hit every time, but then startup time is not impacted.

One of the earliest frameworks that used this approach to generate code was <a href="https://dagger.dev/android.html" target="_blank" rel="noopener">Dagger</a>: it’s a <abbr title="Dependency Injection">DI</abbr> framework for Android. Instead of being runtime-based, it’s compile-time based. For a long time, compile-time code generation was limited to the Android ecosystem.

However, recently, back-end frameworks such as <a href="https://quarkus.io/" target="_blank" rel="noopener">Quarkus</a> and <a href="https://micronaut.io/" target="_blank" rel="noopener">Micronaut</a> also adopted this approach. The aim is to reduce application startup time through compile-time code generation in replacement of runtime introspection. Additionally, Ahead-of-Time compilation of the resulting <em>bytecode</em> to native code further reduces startup time, as well as memory consumption.

The world of annotation processors is huge: this section is a but a very small introduction so one can proceed further if wanted.

A processor is just a specific class that needs to be registered at compile-time. There are several ways to register them. With Maven, it’s just a matter of configuring the compiler plugin:

```xml
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.8.1</version>
      <configuration>
        <annotationProcessors>
          <annotationProcessor>
           ch.frankel.blog.SampleProcessor</annotationProcessor>
        </annotationProcessors>
      </configuration>
    </plugin>
  </plugins>
</build>
```

The processor itself needs to implement <code>Processor</code>, but the abstract class <code>AbstractProcessor</code> implements most of its methods but <code>process</code>: in practice, it’s enough to inherit from <code>AbstractProcessor</code>. Here’s a very simplified diagram of the API:

![Java annotation processor class diagram](https://dev-to-uploads.s3.amazonaws.com/i/s2zaz4vs9fuzjyt0fq4w.png)

Let’s create a very simple processor. It should only lists classes that are annotated with specific annotations. Real-world annotation processors would probably do something useful <em>e.g.</em> generate code, but this additional logic goes well beyond the scope of this post.

```java
@SupportedAnnotationTypes("ch.frankel.blog.*")                   // 1      
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class SampleProcessor extends AbstractProcessor {

  @Override
  public boolean process(Set<? extends TypeElement> annotations, // 2      
               RoundEnvironment env) {
    annotations.forEach(annotation -> {                          // 3      
      Set<? extends Element> elements =
                     env.getElementsAnnotatedWith(annotation);   // 4
      elements.stream()
        .filter(TypeElement.class::isInstance)                   // 5       
        .map(TypeElement.class::cast)                            // 6      
        .map(TypeElement::getQualifiedName)                      // 7       
        .map(name -> "Class " + name + " is annotated with " + annotation.getQualifiedName())
        .forEach(System.out::println);
    });
    return true;
  }
}
```

1. Processor will be called for every annotation that belongs to the `ch.frankel.blog` package
2. `process()` is the main method to override
3. The loop will be called for each annotation
4. The annotation is not as interesting as the element annotated with it.
This is the way to get the annotated element.
5. Depending on which element is annotated, it needs to be cast to the correct `Element` subinterface.
Here, only classes can be annotated, hence, the variable needs to be tested to check whether it's assignable `TypeElement` to access its additional attributes further down the operation chain
6. We want the qualified name of the class the annotation is set on, so it's necessary to cast it to the type that makes this specific attribute accessible
7. Get the qualified name from `TypeElement`

# Conclusion

Annotations are very powerful, whether used at runtime or at compile-time. On the flip side, the biggest issue is that they seem to work like magic: there’s no easy way to know which reflection-using class or annotation processor is making use of them. It’s up to everyone in one’s own context to decide whether their pros out-weight their cons. To use them without any forethinking does a great disservice to one’s code…​ a disservice just as great as discarding them because of misplaced ideology.

I hope this post shed some light on how annotations work, so one can decide for oneself.

The complete source code for this post can be found on [Github](https://github.com/ajavageek/annotation-processor) in Maven format.

<strong>To go further:</strong>

* <a href="https://www.baeldung.com/java-marker-interfaces" target="_blank" rel="noopener">Marker Interfaces in Java</a>
* <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/javadoc/doclet/overview.html" target="_blank" rel="noopener">Doclet Overview</a>
* <a href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.6" target="_blank" rel="noopener">Java Language Specifications: Annotation Types</a>
* <a href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.7" target="_blank" rel="noopener">Java Language Specifications: Annotations</a>
* <a href="https://docs.oracle.com/javase/tutorial/reflect/index.html" target="_blank" rel="noopener">Trail: The Reflection API</a>
* <a href="https://www.baeldung.com/java-annotation-processing-builder" target="_blank" rel="noopener">Java Annotation Processing and Creating a Builder</a>

_First published on April 26th 2020 on [A Java Geek](https://blog.frankel.ch/introductory-guide-annotation-processor/)_