You are here
Home > java >

Annotations In Java

Annotations In JavaBefore the introduction of Annotations, we were extensively using XML for metadata. Using XML for metadata as configurations separates the configuration from the code. At the later stage, when enterprise applications grown up, maintenance of XML was getting inconvenienced. Also, XML loosely couples from the code, in some cases almost separates. Then architects & developers started looking for solutions which can be tightly coupled with the code instead of XML. Then the solution was an introduction to Annotations.

Don’t get confused with the fact that we should always prefer loose coupling as it differs in case of Annotations. You will feel the benefits almost always when you completely understand the topic ‘Annotations In Java’. Just using an annotation instead of creating XML each time creates many differences such as saving your effort & time.

Equally important, Annotations provide a standard way of defining metadata in the code. Prior to annotations people also used their own ways to define metadata. Hence, Annotation normalized the things. Currently most of the frameworks use the combination of both XML and Annotations to take advantage of positive aspects of both. Now Let’s start learning ‘Annotations In Java’.

What is Annotation in Java?

In Java, an Annotation is a form of metadata. We can add it into our java source code. It just behaves like a code about code in Java. An annotation provides supporting information to a Java program. In brief, programmatically annotations are the @interface having parameters/elements/attributes as method declarations. Moreover, we can apply annotations in our classes, fields, methods, parameters, packages etc. JVM preserves these annotations at run-time and read it via reflection. Annotations became available in Java since JDK 1.5.

Annotation without Elements(Empty Annotations)

Empty annotation is the simplest form of annotation. It does not include any element/parameter/attribute. For example @Override, @Entity

Annotation with Elements

The annotation can also include elements, which can be named or unnamed, and there are values for those elements:

@Book(name="Core Java", author="Kathy Sierra")          //Named
public class MyClass( ) { ... }

OR

@SuppressWarnings(value="unchecked")                        //Named
private void myMethod() { ... }

Equally important, If there is just one element named ‘value’ in an Annotation, we can omit the ‘value=’ as below:

@SuppressWarnings("unchecked")                   //Unnamed
private void myMethod() { ... }

However, If the annotation has no elements, then we can omit the parentheses. For example, as in the @Override and @Entity.
Moreover, It is also possible to use multiple annotations on the same declaration as below:

@Author(name = "Craig Walls")
@Book
public class MyClass { ... }

♥ The annotation type can be one of the types that are defined in the java.lang or java.lang.annotation packages of the Java SE API. For example, @Override and @SuppressWarnings are predefined Java annotations. In addition, it is also possible to define your own annotation type. For example, the @Author and @Book annotations in the previous example are custom annotation types. We will talk about custom annotations in later sections.

What are Repeating Annotations?

We come across some situations where we want to apply the same annotation to a declaration repeatedly. As of the Java SE 8 release, repeating annotations permit you to do this.

For example, you are writing code to implement a timer service that allows you to run a periodic cleanup method at a given time or on a certain schedule, similar to the UNIX cron job. Now you want to set a timer to run a method, doCleanup(), on the first day of the month and on every Monday at 11:00 p.m. To set the timer to run, create an @Schedule annotation and apply it twice to the doCleanup() method. The first use of annotation @Schedule specifies the first day of the month and the second specifies Monday at 11p.m., as shown in the following code example:

@Schedule(dayOfMonth="first")
@Schedule(dayOfWeek="Mon", hour="23")                       //Repeating Annotation
public void doCleanup() { ... }

Where we can use Annotations?

Generally we can apply annotations at classes, methods, fields, constructors, parameters etc. Apart from that we can also apply them at declarations. When used on declarations, each annotation often appears on its own line. As of the Java SE 8 release, we can also apply annotations to the use of types. for example, below forms of annotations are type annotations:

new @Interned MyObject();  //Class instance creation expression
myString = (@NonNull String) str; // Type cast
public class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... }  //implements clause
void monitorTemperature() throws @Critical TemperatureException { ... } //Thrown exception declaration

What are Predefined Annotations?

There are a set of predefined annotation types in the Java SE API. Although they are of two types : some are used by the Java Compiler, and some further apply to other annotations.

Annotations Used by the Java Language

@Deprecated 

@Deprecated annotation represents that the marked element is deprecated and should no longer be used. We mainly apply it in a method, class, or field . The compiler will generate a warning message whenever a program uses a method, class, or field with the @Deprecated annotation. When an element is deprecated, we should also document it using the Javadoc @deprecated tag, as shown in the following example. The use of the at sign (@) in both Javadoc comments and in annotations is not accidental: they are related conceptually. Also, note that the Javadoc tag starts with a lowercase d and the annotation starts with an uppercase D.

public class MyClass { 
  // Javadoc comment follows
    /**
     * @deprecated                 // lowercase 'd' for javadoc tag
     * explanation of why it was deprecated
     */
    @Deprecated                    // uppercase 'D' for annotation
    static void deprecatedMethod() { ... }
}

@Override

@Override annotation notifies the compiler that the element needs to override an element declared in a superclass.

 public class MyClass {
   // mark method as a superclass method
   // that has been overridden
   @Override 
   int overriddenMethod() { }
 }

Although it is not necessary to use this annotation while overriding a method as it helps to prevent errors. If a method marked with @Override fails to correctly override a method in one of its super classes, the compiler generates an error. If we don’t apply the annotation, compiler will consider it as a separate method instead of overridden method. Hence, It is always advisable to apply @Override annotation while overriding a method.

@SuppressWarnings

@SupressWarnings annotation tells the compiler to stop specific warnings that it would otherwise generate. Generally there are two cases when compiler generates a warning. The Java Language Specification lists them in two categories for compiler warnings:  unchecked and deprecation. The unchecked warning can occur when associating with legacy code written before the advent of generics. Deprecated warning occurs when we try to use a deprecated element(An element which is no longer in use). In the example below we have two methods. One method is deprecated while other one has legacy code. In either case the compiler usually generates a warning. In both cases, however, the annotation helps in suppressing the warnings.

public class MyClass {
   // use of a deprecated method 
    @SuppressWarnings("deprecation")
    public void useDeprecatedMethod() {
        // deprecation warning - suppressed
        objectOne.deprecatedMethod();
    }
        // use of a legacy code written before the introduction of generics
    @SuppressWarnings("unchecked")
    public void useLegacyCode(){
        // legacy code warning - suppressed
        List list = new ArrayList();
    }
}

Further, to suppress multiple categories of warnings, we can use the following syntax:

@SuppressWarnings({"unchecked", "deprecation"})

@SafeVarargs

@SafeVarargs annotation, when applied to a method or constructor, asserts that the code does not perform potentially unsafe operations on its varargs parameter. Using this annotation type means ignoring unchecked warnings relating to varargs.

@FunctionalInterface

@FunctionalInterface annotation, introduced in Java SE 8, tells to the compiler that the type declaration is a functional interface, as defined by the Java Language Specification. For more details on Functional Interface kindly visit the internal article.

Annotations That Apply to Other Annotations (Meta-annotation)

We also call them meta-annotations because they apply to other annotations. There are multiple meta-annotation types defined in java.lang.annotation.

@Retention

@Retention annotation represents the retaining level of annotation such as source, class or runtime. It tells compiler whether annotation will be part of .class file or not. There are three possible options as given below.

1) RetentionPolicy.SOURCE – The marked annotation retains only in the source level and will not be part of your .class file.

2) RetentionPolicy.CLASS – The compiler retains marked annotation at compile time, but the Java Virtual Machine (JVM) ignores it.

3) RetentionPolicy.RUNTIME – The JVM retains the marked annotation so it can be used by the runtime environment. Hence the functionality of annotation will exist at runtime for sure.

♦ Please note that these values are coming from enum RetentionPolicy.java. Below is the code :

/** A mirror of java.lang.annotation.RetentionPolicy. */
public static enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

@Target

@Target annotation indicates the part of your Java program where the Annotation applies like class, method, field, constructor, parameter etc. if Target value is set to ‘TYPE’, it means it is applicable only at the class level. Generally a target annotation specifies one of the following element types as its value. Further to check all possibilities please check the latest ElementType.java class from Javadoc.

1) ElementType.ANNOTATION_TYPE : We can apply it to an annotation type.
2) ElementType.CONSTRUCTOR : We can apply it to a constructor.
3) ElementType.FIELD : We can apply it to a field or property.
4) ElementType.LOCAL_VARIABLE : We can apply it to a local variable.
5) ElementType.METHOD : We can apply it to a method.
6) ElementType.PACKAGE : We can apply it to a package declaration.
7) ElementType.PARAMETER : We can apply it to the parameters of a method.
8) ElementType.TYPE : We can apply it to any element of a class.

♦ Please note that these values are coming from enum ElementType.java. These values may differ after the introduction of new JDK version. Below is the code as of JDK 14:

public enum ElementType {
/** Class, interface (including annotation type), enum, or record declaration */
TYPE,

/** Field declaration (includes enum constants) */
FIELD,

/** Method declaration */
METHOD,

/** Formal parameter declaration */
PARAMETER,

/** Constructor declaration */
CONSTRUCTOR,

/** Local variable declaration */
LOCAL_VARIABLE,

/** Annotation type declaration */
ANNOTATION_TYPE,

/** Package declaration */
PACKAGE,

/**
* Type parameter declaration
* @since 1.8
*/
TYPE_PARAMETER,

/**
* Use of a type
* @since 1.8
*/
TYPE_USE,

/**
* Module declaration.
* @since 9
*/
MODULE,

/**
a preview feature of the Java language. Programs can only use this
constant when preview features are enabled. Preview features
may be removed in a future release, or upgraded to permanent
features of the Java language.}
* @since 14  */

RECORD_COMPONENT;
}

@Documented

@Documented annotation indicates that the element needs documentation using the Javadoc tool. However By default, annotations are not included in Javadoc. Whenever a Java element has @Document, it means that element will be part of documentation using the Javadoc tool. For more information, see the Javadoc tools page.

@Inherited

@Inherited annotation indicates that we can inherit the annotation type from the super class. However this is not true by default. When the user queries the annotation type and the class has no annotation for this type, the class’ superclass is queried for the annotation type. This annotation applies only to class declarations. Note that this meta-annotation type has no effect if the annotated type applied to annotate anything other than a class.

@Repeatable

@Repeatable annotation, introduced in Java SE 8, indicates that we can apply an annotation more than once to the same declaration or type use. For more information, see Repeating Annotations.

How to create Custom Annotations in Java?

For more details please check  Section 9.6.1 of the Java Language Specification

In order to create a custom or user defined annotation, we need to collect two important details : Retention Policy and Element Type. We have already discussed about these terms in detail in above sections. Next you need to keep some rules in you mind while creating a custom annotation as below.

General Rules to create Custom Annotations

1) We can create an Annotation by using @interface, followed by annotation name.

2) An annotation will have @Retention and @Target as meta-annotations.

3) Annotation has exactly one associated retention policy.

4) An Annotation can have more than one targets associated with it.

5) All annotations extend java.lang.annotation.Annotation interface. Annotations can’t include any extends clause.

6) Annotations may also have associated parameters/attributes/elements. These parameters are represented by method declarations inside the body of annotation type. We should not provide implementation for these methods. The return type of a method declared inside an annotation type must be one of the following, or a compile-time error occurs:
A primitive type, String, Class, An enum type, An annotation type, or An array of any of the five preceding types.

To distinguish an annotation type declaration from a normal interface declaration, the keyword interface is preceded by an at-sign (@) in an Annotation.

Example#1 

Let’s consider a sample annotation example in order to create the custom annotation.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Book {
      public String title() default "Spring in Action";
}

In the example above, the body of the annotation declares a single String parameter, named ‘title’, that has a default value of “Spring In Action”. Important point of notice in the above example is that the variable ‘title’ has a special meaning as it defines a Single-Element Annotation (Section 9.7.3. of the JLS). This allows you to use this annotation without specifying the name of the parameter. For example, you can annotate a field using @Book(“Core Java”) instead of @Book(title=”Core Java”). Although, we can also write it like the latter but it’s not mandatory.

The inclusion of a default value of string allows you to ignore the value, resulting in value holding the default string if no value is explicitly specified. For example, if a user declares the above annotation using the form @Book, then the title parameter is set to “Spring In Action” string by default.

If we have to apply the above annotation to a class then we would do it like this:

@Book("Core Java") 
public class MyClass { ... }

  OR 

@Book(title="Core Java") 
public class MyClass { ... }

  OR 

@Book
public class MyClass { ... }

Example#2

Let’s consider another example in order to create the custom annotation.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Book {
      public String title() default "Spring in Action";
      public String author();
      public double version();
}

If we have to apply the above annotation to a class then we would do it like this:

@Book(
    title="Core Java",
    author="Kathy Sierra",
    version=1.0
)
public class MyClass { ... }

 OR 

@Book(
 author="Kathy Sierra",
 version=1.0
)
public class MyClass { ... }

As you can see, we have not given any value to the ‘title’ elements as it is optional to set the values of default elements. But if you want you can assign new value while using annotation just the same way as we did for other elements. However we have to provide the values of other elements that do not have default values set while using annotation.

Example#3

Let’s consider an example of a custom annotation at method level with array elements.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Book {
      int count();
      String[] titles();
}

If we have to apply the above annotation to a method then we would do it like this:

 public class MyClass { 
 
     @Book( 
         count=3,
         titles={"Core Java", "Spring In Action"}
     )
     public void getBookDetails() {
                ...
     } 
}

Summary

After going through all the theoretical & examples part of ‘Annotations in Java’, finally, we should be able to understand the concept of Annotations. Also we should be able to create custom annotations. Of course, In this article we have thoroughly learned about the Annotations. Similarly, we expect from you to further extend these examples and implement them in your project accordingly. Additionally, If there is any change in future, we will update the article accordingly. Moreover, Feel free to provide your comments in comments section.

 

close

5 thoughts on “Annotations In Java

  1. Please elebrote the one article for creating the custome collection required is it possible then like hashmap,arraylist ,linked hashmap .

Leave a Reply

Top