You are on page 1of 12

1) Introduction

Annotations in Java is all about adding meta-data facility to the Java Elements. Like
Classes, Interfaces or Enums, Annotations define a type in Java and they can be applied
to several Java Elements. Tools which will read and interpret the Annotations will
implement a lot of functionalities from the meta-information obtained. For example, they
can ensure the consistency between classes, can check the validity of the paramters
passed by the clients at run-time and can generate lot of base code for a project. This
article provides you a complete guide detailing the various aspects of Annotations. The
topics covered in this article are as follows,

• Page - 1Introduction to Java 5.0 Annotations
• Page - 2 Built-in Annotations in Java
• Page - 3User-defined Annotations
• Discuss Here

2) Java Annotations

2.1) Introduction

Java, being a wonderful object-oriented language provided support for Annotations
starting from 5.0. This feature was added to Java 5.0 as a result of the JSR 175 namely "A
Metadata Facility for the JavaTM Programming Language". Annotations in Java can be
seen elsewhere in a program. It can be seen in class declaration, method declaration, field
declaration etc. The added Annotation to Java Elements have proven themselves to be
considerably useful in many instances. Consider the following class definition,

final class Employee
private String name;
private String id;

// Getters and setters for Employee class.

The above is a definition of a class, Employee. It can be noted that the class declaration is
preceded with the final keyword which tells that this class cannot be sub-classed. So,
the introduction of the final keyword adds some additional information (or adds some
constraints) over the class definition telling that no other class in the word can extend the
Employee class. Therefore, the final keyword forms a part in providing meta-data
information in the class definition. So, this is one variation of Annotation. Annotations
are generally a way to add meta-data information to an element (an element can be a
class, method, field, or anything) and these meta-data are processed by the tools
(compilers, javadoc, etc.). Annotations are differentiated from other elements like class,
interface etc., by preceding an '@' symbol before it.

An annotation definition looks like the following,

• PARAMETER – Applied only to method parameters in a method definition. • ANNOTATION_TYPE – Applied only to Annotation Types. • PACKAGE – Applicable only to a Package. A Type can be a Java class or interface or an Enum or even an Annotation. • METHOD – Applied only to methods. The Meta-Annotations that would be covered in the forthcoming sections @Target(ElementType. if the case is that @TestAnnotation annotation can only be applied to methods. • LOCAL_VARIABLE – Can be applicable only to Local variables. which is defined in a well-defined Enum called ElementType. This is referred to as Annotating an Annotation itself. the following is the declaration of the @TestAnnotation annotation along with some meta-data that states the elements that this annotation can be applied to. (Variables that are declared within a method or a block of code). public @interface TestAnnotation { // Property Definition here. The argument to @Target Annotation can be one from the possible set of values of any Java Element. TestAnnotation.2) Target Annotation For example. This kind of Annotation Chaining is always possible.METHOD) public @interface TestAnnotation { // Property Definitions here. It has nothing to do with annotations. For example. '@' along with interface is the start of the annotation definition and TestAnnotation in the above case is the name of the Annotation. Here are the possible values taken by this Enum. } From the above. . } Don't get confused with the interface keyword. or a method (method-level annotation) or a field (field-level annotation) is specified in the declaration of the annotation itself. The target element tells that the @TestAnnotation annotation can be applied only to methods and not to any other element types. • Target Annotation • Retention Annotation 2. then there is a Meta-Annotation (meta-data about meta-data) which tells for which element type this annotation is applicable. • FIELD – Applied only to Java Fields (Objects. we can see that the Annotation @TestAnnotation is annotated with @Target. Whether annotations can be applied to class (a class-level annotation). • CONSTRUCTOR – Can be applicable only to a constructor of a class. • TYPE – Applied only to Type. declared at class level). Instance or Static.

then the compilers can report them as errors.RUNTIME) public @interface Override { } @Override annotation essentially tells to the compiler that. • Retain the Annotation Definition during the Run-time so that JVM can make use of it.CLASS) public @interface TestAnnotation { // Property Definitions here.1) The @Override Annotation The syntax of the @Override annotation is as follows. we can define something like this. } 3) Built-in Annotations in Java There are some pre-defined annotations available in the Java Programming language.METHOD) @Retention(RetentionPolicy.CLASS) @Target(ElementType. • Override • Deprecated • SuppressWarnings @Retention(RetentionPolicy. The three possible ways of telling this are. The Annotation that is used to achieve this is @Retention and it takes a possible values of SOURCE. For example. Assume that we have some Annotations defined in the source code. then that method must be an overridden method. whenever such an annotation is defined in a method of some class. They are. TestAnnotation.2. if we want to retain the @TestAnnotation information till the class file. If not. Consider the following sample which explains this. Override. CLASS and RUNTIME defined in RetentionPolicy Enumeration.3) Retention Annotation Another commonly used Meta-data for an Annotation is the Retention Policy. . We have a mechanism through which we can say that to what extent the Annotations should be retained. • Retain the Annotation in the Source Code only • Retain the Annotation in the Class file @Target(ElementType.

consider the following sample code. The major aim of introducing this annotation @Override is to catch the errors that programmers might make when overriding a method in the sub-class. } } Manager. At this point. So. A class. These methods have been marked as protected so that sub-classses can override them by providing their own functionality. Manager is created and the methods are overriden in the sub-class. } @Override protected void endWork() { // Code to end the work. If no such method is found in the base class. The methods startWork() and endWork() has been annotated with @Override annotation. } } In the above sample public class Manager extends Employee { @Override protected void startWork() { // Code that will start to do some work. public class Employee { protected void startWork() { // Code that will start to do some work. . we have a class called Employee with two methods namely startWork() and endWork(). This tells to the compiler that the method that is annotated with @Override is an overridden method.Employee. } protected void endWork() { // Code to end the work. we have to note one key issue. For example. the compiler immediately climbs up to the base class to find the existence of such a method. Object value. then the compiler can report an error public class DefaultTableCellEditor implements TableCellEditor { public Component getTableCellEditorComponent (JTable table.

0. then a new class has to be created by extending the DefaultTableCellEditor as shown below. boolean isSelected.util. Developers would have wasted their energy and time in debugging what was wrong with the code and why the expected behavior wasn't the customized functionality. int column){ // My customized functionality goes here. These kind of errors can be found at the compile-time rather than at the run-time. LegacyCode.suppress. int column) { // Default functionality goes here.*.java public class MyCustomizedTableCellEditor extends DefaultTableCellEditor { public Component getTableCellEditorComponet(JTable table. but not with the expected behavior because of the fact that when re-defining the method in the sub-class the method name has been wrongly spelled (getTableCellEditorComponet() instead of getTableCellEditorComponent()). import java. Else the compiler will issue a warning message. boolean isSelected. then the compiler will immediately report an error message like. If the method is annotated with @Override and if there is an mismatch in the method name or in the argument package builtin. references to any of the Collection types should be parameterized. public class LegacyCode . if the annotation @Override is applied on the re-defined method in the sub-class. } } If the functionality of the getTableCellEditorComponent() has to be overriden. } } The above code compiles and run fine. For example. "The method getTableCellEditorComponet of type 'MyCustomizedTableCellEditor' must override a super-class method". int row. consider the following legacy code which makes use of a raw List type. int row. Object value. MyCustomizedTableCellEditor. 3.2) The @SuppressWarnings Annotation With the concept of Generics starting from Java 5.

one can define the return type like List<Object> thereby making the compiler happy. it provides a hint to the Compiler to turn-off the warnings. References to generic type List<E> should be parameterized". } The above code provides a hint to the compiler to suppress the unchecked warnings. then we would probably see a message something very similar to this. } Note that Suppress Warnings can be used on various Java elements like Class/Interface. @SuppressWarnings("unchecked") public static List toList(Object[] array) { return Arrays. We can see numerous of warning like this. { public static List toList(Object[] array) { return Arrays.0 compiler. The compiler suggests not to use raw type for Collection without being parameterized with some package @Target({TYPE. Consider the case where a project is depending on a third-party public @interface SuppressWarnings { String[] value(). PARAMETER. Assume the case of legacy projects when its get compiled by a Java 5. . Following is another example of Suppress Warnings. CONSTRUCTOR. import java. We know that it is a good practice to provide a Serial Version Identifier for a class that implements the Serializable interface. Consider the following code. SuppressWarnings.suppress.Serializable.asList(array). "List is a raw type. When applied on any of the Java Elements along with a value. FIELD. The solution for this problem is to make use of @SuppressWarnings Annotation. Consider the following code. Constructor etc. For getting rid of this warning message. It is highly impossible to go and fix everywhere. } } If the code gets compiled by using a Java 5 Compiler. The following shows the definition of a Suppress Warning Annotation. LegacyCode.asList(array). METHOD. LOCAL_VARIABLE}) @Retention(RetentionPolicy. in which case the dependant source code cannot be changed. Method.

public class LegacyCode implements Serializable { @SuppressWarnings("unchecked") public static List toList(Object[] array) { return Arrays. Clients may prepare themselves not to depend on the old method package builtin. LegacyCode.3) The @Deprecated Annotation The Interfaces and the Classes in an Application get updated every now and @SuppressWarnings("serial") public class LegacyCode implements Serializable { } Note that in the above case the Annotation is applied in the class-level. For example. */ . } } The compiler will warn saying that for a Serializable class. there should be a definition of Serial Version Identifier like this :"The serializable class LegacyCode does not declare a static final serialVersionUID field of type long". 3. public class MyOldClass { /** * This method has become obsolete. import java.*. Client Applications now can * depend on * {@link #myAlternativeMethod()} to achieve the same affect.util. But this solution has a huge impact on the code that is dependant on this interface.asList(array).deprecated. consider the following code. This can be suppressed (although its not a good practice) by using the following Annotation. Imagine the case where a method defined in a class or an interface has now become obsolete and we should warn the Client Applications not to make use of them. MyOldClass. Another elegant way is to mark the old method as deprecated which informs the client not to use this method anymore because in the future versions this old method may not be supported. One dangerous way is to remove the method itself from the Interface. Interfaces used by the Clients may undergo so many revisions in the form of new methods being added and existing methods being removed or updated.

We can have a property called fileName within the declaration of Annotation itself. For example.txt") Movie movie. The above code tells to save all the information about the Movie object to the file called movies. It is always nice to mention the alternate ways in the JavaDoc itself. "The method myDeprecatedMethod() from the type MyOldClass is deprecated".txt. let us see how to apply this Annotation on Java Elements. Now if any of the Client code tries to access this method. @Persistable(fileName = "movies. @Deprecated public void myDeprecatedMethod() { // Obsolete code here.FIELD. Consider the following code snippet. } public void myAlternativeMethod() { // Revised code here. 4) User-defined Annotations In this section. But who will do this operation? We haven't defined any code that will do . Imagine that we want to persistent object information to a file. An Annotation called Persistable can be used for this purpose. An important thing is that we want to mention the file in which the information will get stored. in this case) followed by the property name which looks like a method definition fashion. } } The class MyOldClass has a method myDeprecatedMethod() which is tagged as Deprecated.LOCAL_VARIABLE}) public @interface Persistable { String fileName(). then the following warning message is issued by the compiler. The type ( @Target({ElementType. Also note how the property fileName for this Annotation is defined. the JavaDoc for myDeprecatedMethod() method suggests to use the method myAlternativeMethod() as an alternative. ElementType. } Note that we have specified the target for this Annotation as Field and Local variable meaning that this Annotation can be applicable only to Java Fields and Local variables. Persistable. The definition of the Persistable Annotation is given below. Having defined this Annotation. we shall see how to annotate objects that we may come across in day-to- day life.

This interface is primarily used to tell that the element in consideration is an Annotation Element which means that all the existing classes/interfaces like java. java. Now let us see the syntax of specifying multiple values to a property. then the default value defaultMovies. they will perform the required operation. From Java 5. .Method implement the AnnotationElement interface. Java Reflection API is used to dynamically discover information (meta-data information too) for any type of Java Element like Class.lang. As we all know.txt".txt". then we should follow the strange syntax. java.FIELD.lang.txt is @Target({ElementType.lang.txt". } In this case.this operation. Following are the useful methods available in the AnnotationElement interface.Field and java. If we want to give default values to a property. if the clients didn't supply a value to the fileName property. ElementType.FIELD. Interface.LOCAL_VARIABLE}) public @interface Persistable { String[] fileNames().1) Introduction In this section. let us see how to query for information related to Annotation types using Reflection.annotation package. Method. Persistable. } And now Clients can given multiple file entries using the traditional array syntax like this. 5) Reflecting the Annotation Information 5.lang.reflect. Constructor etc.reflect. @Persistable( fileNames = { "movie1.reflect.lang. ElementType.Class. A new interface called Annotated Element (AnnotationElement) has been added to the java.Constructor. Generally Annotations are interpreted by Tools and once Tools read these Annotation informations. @Target({ElementType. the Reflection API has been extended to add support for Annotation types too. "movie3.txt"} ) Movie movie. Persistable.0 onwards. Let us assume that we want to save the status of the object in multiple files in which case we should have declared an array to hold the filenames. java.LOCAL_VARIABLE}) public @interface Persistable { String fileName() default "defaultMovies. "movie2.

CONSTRUCTOR. ElementType.annotation.annotation. import java.CONSTRUCTOR.lang. @Target(value = {ElementType. gives the corresponding Annotation object.lang. import package reflections.Retention. import java.ElementType. The presence of Target Annotation tells that Author Annotation can only be applied to Java elements like Constructor. @Target(value = {ElementType.lang. import java. For this example. • Annotation[] getAnnotations() – Returns an array of Annotations that are present on the calling object.*. The name property is also given a default value unknown if the consuming Application fail to provide an explicit value.METHOD. • Boolean isAnnotationPresent(Class) – This method will return true if the annotation type (which is passed as an argument) is present in the calling element object. let us define two Annotation types as follows.RetentionPolicy.annotation.METHOD. } Note the definition of the Author annotation. ElementType.lang.2) Example Program Let us look into a simple example program that makes use of the new interfaces and the methods to query for Annotation information at run-time. Following is the definition of the Version Annotation. Method and Type (Class/Interface). 5. This is a very common piece of meta-information that can be given to any Java file (or any other type of file). Author. Version. ElementType. Also make a note of the Target Annotation. Another important thing to note is the Retention for this Annotation is set to Run-time because we want this Annotation information to be available to the JVM while the program is running.Target.annotation.annotation. It looks exactly the same as Author Annotation except the fact that it has a property called number (which is of type double) to hold the version value.lang.TYPE}) .RUNTIME) public @interface Author { String name() default "unknown".TYPE}) @Retention(RetentionPolicy. ElementType. import java. • Annotation getAnnotation(Class) – When given an Annotation class on the calling element. This is a single-valued Annotation meaning that this Annotation has a single property called package reflections. One is the Author Annotation and the other is the Version Annotation.

@Retention(RetentionPolicy.getMethod("annotatedMethod1".lang.0) public void annotatedMethod2() { } } This program makes use of the new API to read the Annotation related information that are applied on various Java package reflections. Then the array is iterated to get the individual element. public class AnnotationReader { public static void main(String args[]) throws Exception { Class<AnnotatedClass> classObject = AnnotatedClass. AnnotatedClass. then made a downcast to extract the exact information .0f) public void annotatedMethod1() { } @Author(name = "Author2") @Version(number = 4. import java.0) public class AnnotatedClass { @Author(name = "Author1") @Version(number = 2. @Author(name = "Johny") @Version(number = 1.lang.class. The Annotations are applied at the class-level as well as in the method- level.Method. The utility method readAnnotation() takes a parameter of type AnnotationElement which can represent a Class. new Class[]{}). .reflect.RUNTIME) public @interface Version { double number().lang. import java. Method method1 = classObject. Then it queries for a list of Annotations of that particular element by calling the getAnnotations() method.Annotation. readAnnotation(classObject).Author.annotation.reflect.AnnotatedElement. method or package and Version. import java. AnnotationReader. } Let us have a look at the following class definition that makes use of the above declared Annotations.number().

new Class[]{}).lang. System.println("Author name:" + author.getAnnotations(). Method method2 = classObject. Annotation[] classAnnotations = element.lang.reflect.out.0 .getName()).reflect.getClass(). } } } catch (Exception exception) { } } } The output for the above program is as follows. } else if (annotation instanceof Version) { Version version = (Version)annotation.number()).println("Version number:" + version. System. for(Annotation annotation : classAnnotations) { if (annotation instanceof Author) { Author author = (Author)annotation. Output Finding annotations on java. } static void readAnnotation(AnnotatedElement element) { try { System.out. readAnnotation(method2).0 Finding annotations on java.println("\nFinding annotations on " + element. readAnnotation(method1).Method Author name:Author1 Version number:2.printStackTrace().getMethod("annotatedMethod2".Method Author name:Author2 Version number:4.Class Version number:1.0 Author name:Johny Finding annotations on java.