Original URL: https://www.theregister.com/2006/02/24/java_annotations/

Of Java Annotations

Drawbacks and drawfronts

By John Hunt

Posted in Software, 24th February 2006 12:46 GMT

The J2SE 5.0 release of Java introduced many new language features, one of which is called annotations. At the time I noted their presence, but did not feel particularly excited about their appearance. Now that a little water has flowed under the bridge, I think it is time to revisit Java Annotations.

In this column we will look at what a Java annotation is, what they are used for, how you actually use them in your Java code an dhow you can define your own. We will follow this by considering some of the drawbacks of Java annotations.

Java Annotations

Annotations are presented as metadata – that is data about data. In the case of Java this means that they provide information about various elements of a Java class. For example, they may annotate a method, class or instance variable. One example of an annotation is to note that a method has been deprecated, or that it overrides a method in the superclass. These annotations can then be used by an annotation processing tool (such as APT), or an IDE (such as Eclipse) or indeed a framework, to validate, configure or add to the original Java. For example, if you have annotated a method as overriding a parent class method, then the annotation processing can confirm that you are indeed overriding a method.

There are seven annotations provided in the J2SE 5.0 release (see the annotations guide here; these are provided in two packages, java.lang and java.lang.annotation:

In the package java.lang there is:

@Deprecated – indicates that the associated Java element has been deprecated. It is an alternative to using the Javadoc @deprecated element. A deprecated method or class is essentially one that should no longer be used and that is not guaranteed to be available in future versions of the software. It is thus often useful to know that you are using “old” versions of an API. Although the use of the Javadoc tag already allows many tools (such as Eclipse) to indicate that a language feature is deprecated, the use of the @Deprecated annotation makes this simpler and allows a wider range of tools to report on the use of deprecated features.

@Override - indicates that the method should override a method in the superclass.

@SuppressWarning – directs the compiler to suppress the specified warning.

In the package java.lang.annotaiton:

@Documented – directs tools to automatically generate Javadoc for the annotated element (e.g. a method or variable).

@Inherited – this indicates that the associated annotation is inherited by subclass of the current class.

@Retention – indicates how long annotations with the annotated type are to be retained. For example, a retention type of RUNTIME indicates…

@Target – This indicates the Java element to which associated annotations apply.

It is also possible to extend the set of annotations available by defining your own annotations. This enables project, task and company specific annotations to be created.

What are annotations for?

Annotations are intended to provide three basic facilities. These facilities are:

• The provision of additional semantics for various class elements. This additional semantic information can help developers to understand the intent behind some feature or implementation detail.

• The execution of additional compile time checks that ensure various constraints are met.

• The support of additional code analysis by annotation-aware tools.

None of these requirements are new and indeed many developers have found ways of overcoming the lack of any annotation-like feature in previous versions of Java.

For example, I have tended to make extensive use of Marker Interfaces over the last few years. These are interfaces that may not contain any methods, but are used to denote a particular concept or entity within an application. This is not a particularly radical idea and indeed there is an example of such an interface in the Java language itself - the java.io.Serializable interface. This interface is a marker interface in that it does not require any methods to be implemented but indicates that a class is capable of being serialized via the Java Serialization mechanism.

Such marker interface can now be replaced with annotations. We can define our own annotation that can be used to mark a class as being a particular concept or entity etc.

Using annotations

Annotations are straightforward to use; they merely require that an appropriate annotation type be placed directly before the Java language element being annotated. For example:

public class Person {
@Override
public String getName() {
    return this.name;
}
}

This means that when this code is compiled, or when it is analysed by tools such as Eclipse, a check can be made to ensure that the method getName() does override a method in the class Person’s superclass. In this particular case, the class Person extends the class Object as a default. The class Object does not contain a method getName() and thus it does not override such a method. This therefore results in an error message being generated. For example, in figure 1 Eclipse has identified that the method getName() should override a method in the parent class and has provided a pop up to this effect.

Screenshot showing Eclipse analysing annotations

However, marking which methods you expect to override parent class methods is probably a step two far for many developers. A rather more useful annotation may be the @SuppressWarnings annotation.

The @SuppressWarnings annotation can be very useful if you have some code that uses a deprecated method or class (possibly because it has been in your system since before that method was deprecated) and you do not want the compiler to churn out lots of warnings about using deprecated APIs. By using the @SuppressWarning annotation and the parameter value “deprecation” it is possible to suppress (turn off) the production of the deprecated warning. For example:

@SuppressWarnings("deprecation")
public static void terminateProcess() {
    Thread.currentThread().stop();
}
 

Defining your own annotations

You can easily create your own annotations by defining a new annotation type. This is done using a new piece of language syntax, the @interface key word. For example, to define a new annotation @Auditor we would define the following annotation type.

public @interface Auditor {
    
}
 

Note that although the syntax for this is almost exactly the same as for a standard interface, the “@” symbol at the start of the keyword changes this to be an annotation declaration. When you compile the resulting Auditor.java file this creates a standard Auditor.class file. If you place this class file on your class path, then you can use this new annotation type within your Java code. For example, if you place the @Auditor just before the class declaration, this marks the class as being of the entity type Auditor. This is illustrated in Figure 2.

A screenshot showing the use of the @Auditor annotation

You can also define parameters that can be used with annotations, and accessor methods for retrieving information about the options specified with an annotation.

Drawbacks of Annotations

Annotations are not without their drawbacks. Not least of which is that they are not really metadata – that is they are not data about data – they are data about classes, methods, instance and static variables etc.

Window dressing

As such annotations are syntactic sugar – they coat the elements of a class without actually telling you anything in detail about that class (you can use the reflection API for some of that). Thus they provide guidance to processors, tools and frameworks to help in the analysis, compilation or deployment of that software.

Inheritance

One of the major features of an object-oriented system is inheritance. You can subclass a class, and subclass an interfaces – but you can’t subclass annotations.

Null values

If a null value should be treated as an un-initialized value then annotations are somewhat awkward in the way they handle these – rely on the developer to provide a way of indicating un-initialised rather than initialised to null.

Values in General

These are somewhat limited in what you can use – although in the main this is fine.

Annotations hold constants

The values used with annotations are hard coded rather than variable. Thus if an annotation takes a literal value of 40 – then that value is now hard coded into your program.

Annotations and code synchronization

Just as with Javadoc comments themselves, annotations need to be maintained to reflect any code changes that may occur. However, as we all know, it is all too easy to change the source code and not to update the associated Javadoc (even when they are next to each other). Exactly the same is true for annotations. If the code relating to an annotation changes, then the associated annotation may also need modification. This may not be as straightforward as it seems. For example, if I rename a method in a class I am working on, then this may impact on another class, that I may know nothing about; if that class requires that one of its methods overrides mine (due to the use the @Override annotation). Of course this may be what is desired or it may not! As you can define your own annotations this situation may become much worse, with significant repercussions for on-going maintenance, clarity and general stability of the code.

Summary

So where does that leave the question “To Annotate or not to Annotate?”. In essence, as with many things in life, annotations can be very useful but should not be over used or abused. They can add extremely useful additional information to Java code that can be analysed by tools, frameworks, analysers as well as developers themselves – but they should not be used without due consideration. ®

Further reading

A discussion of Annotations here.

A critique of Annotation weaknesses here.