Java Annotations

In this tutorial, we’ll discuss regarding the Annotations in Java and its differing types.

Introduction

In the Java language, an annotation may be a type of syntactic metadata that can be added to Java ASCII text file, though they’re not a part of the program itself. Methods, variables, parameters, Classes and Java packages may be annotated.

Annotations were added to the Java language from JDK 5. Annotation clearly has no visible impact on the output or execution of the code they annotate i.e they do not affect the execution of the program. Annotations begin with a @ sign.

Syntax : @AnnotationName

Annotations don’t seem to be pure comments as they can modify the approach a program is treated by the compiler.
For Example:

class Parent_Class 
{ 
	public void display() 
	{ 
		System.out.println("Parent_Class display()"); 
	} 
} 
class Child_Class extends Parent_Class 
{ 
	@Override
	public void display(int x) 
	{ 
		System.out.println("Child_Classs display(int )"); 
	} 

	public static void main(String args[]) 
	{ 
		Child_Class o = new Child_Class(); 
		o.display(); 
	} 
}

Output:

Error: method does not override or implement a method from a supertype

We see that the program gives an error but if we remove parameter (int x) or we remove @override, the program compiles fine.

What is the use and why do we use Annotations?

1. Directions to the compiler: There are three inherent-in annotations out there in Java (@Deprecated, @Override & @SuppressWarnings) that may be used for giving bound directions to the compiler.

2. Compile-time instructors: Annotations provide compilation-time directions to the compiler that may be further utilized by software build tools to generate code.

3. Runtime instructions: We are able to outline annotations to be out there at runtime which we are able to access using java reflection and might be used to offer instructions to the program at runtime.

Types of Annotations

1. Predefined or Built-in annotations

@Deprecated
@Override
@SuppressWarnings
@SafeVarargs
@FunctionalInterface

2. Meta-annotations

@Retention
@Documented
@Target
@Inherited
@Repeatable

3. Custom annotations

Now we’ll study type one by one very well.

1. Predefined or Build in- annotations:

A predefined annotation exists as part of Java. You will find these annotations within the java.lang.annotation package. To use them, you have to add import java.lang.annotation.*; to the start of your application or program.

1.1 @Deprecated:

This annotation indicates that the marked component is deprecated and may not be used. The compiler generates a warning when a program uses a method or field with @Deprecated annotation or a class. It is very normal to additionally add some Javadoc next to the @Deprecated annotation to elucidate that what would be a far better option that serves the proper behaviour. We are able to communicate the deprecated standing within the documentation yet by using the Javadoc @deprecated tag. The utilisation of the @ sign in each and every Javadoc comments and in annotations also isn’t coincidental because they are connected conceptually. The Javadoc tag starts with a d in lowercase and the annotation starts with an D in uppercase.

    /**
     * @deprecated
     * explain why it is deprecated
     */
    @Deprecated
    static void Method() { }

Java 9 adds some elective attributes to the @Deprecated annotation: since and for removal. The since attribute needs a string that lets us outline in which version the component was deprecated. The default price is an empty string. And for removal is a boolean that enables us to specify if the component is eliminated in the next release. The default value is false.

1.2 @Override:

The @Override annotation is a default Java annotation and it will be introduced in Java 1.5 Version. The @Override annotation mentions that the child class method is over-writing its parent class method. If this annotation is present and the superclass is deficient of an element of the same name, the compiler outputs an error in order that you can recognize that something is wrong with the override. The most important reason why we have the tendency to use the @Override annotation is it extracts warning from the compiler and additionally improves the readability of the code.
For Example:

class Food {
  public void display() {
    System.out.println("I am Food");
  }
}
class Indian extends Food {
  @Override
  public void display() {
    System.out.println("I am an Indian Cuisine");
  }
}
class Main {
  public static void main(String[] args) {
    Indian i1 = new Indian();
    i1.display();
  }
}

Output:

I am an Indian Cuisine

Generally, novice developers overlook this feature because it isn’t necessary to use this annotation while overriding the method. Even though we do not use this @Override annotation, the program will still run fine without any errors. So the question is why do we use the Annotations.

The answer to this question is:

1) If technologists make any kind of mistakes like wrong parameter types or wrong method names while overriding, you will get a compilation error. By using this the annotation will tell the compiler that you are overriding this method. If you will not use the annotation then the subclass method will behave as a new or replacement method in the subclass.

2) It improves the readability of your code. If you have got lots of classes in your application then this annotation would assist you to spot the classes that need modifications when you change the signature of a method.

1.3 @SafeVarargs:

Java 5 introduced the thought of varargs, or a method parameter of variable length, yet as parameterised types.Java 7 introduced the @SafeVarargs annotation to suppress the unsafe operation warnings that arise once a method has varargs (variable number of arguments).

In easier terms, it has the potential to perform operations that are not safe on the arguments passed to a method or constructor. This annotation says that the code does not do anything unsafe and therefore it does not need all the usual or regular checks. Reducing the number of checks makes the application run fast. Java 9 extended the utilization of @SafeVarargs annotation, it will currently be used with private methods as well. This is because non-public or private methods can’t be overridden.
Example Code when we don’t use @SafeVarargs:

import java.util.*;  
public class test{  
    private void print(List... colors) {  
        for (List color : colors) {  
            System.out.println(color);  
        }  
    }  
    public static void main(String[] args) {  
        test obj = new test();  
        List l = new ArrayList();  
        l.add("Blue");  
        l.add("Black"); 
        l.add("White");
        obj.print(l);  
    }     
}

On compiling this code provides warning messages but it compiles without errors.
Output:

[Blue, Black, White]

The warning which we get on compiling the code is:
Type safety: Potential heap pollution through varargs parameter names
Type safety: A generic array of List is made for a varargs parameter

Code after using @SafeVarargs:
The same code as above and the same output as above but without and warnings.

1.4 @SuppressWarnings:

@SuppressWarnings annotation is one of the three built-in annotations available in JDK and added with the @Override and @Deprecated in Java 1.5. The Java compiler outputs a lot of warnings to signal potential issues. For instance, if you attempting to use a deprecated method in your code, the compiler outputs a warning message regarding it. In case if you do not need to urge any warnings from the compiler for the known things, then you’ll be able to use @SuppressWarnings annotation. For example, you are calling the deprecated method, and you know that its deprecated, therefore to avoid compiler warnings, use @SuppressWarnings annotation.
For Example:

public class Deprecate {     
    @Deprecated
    public void showDM(){
        System.out.println("Method Deprecated");
    }     
    @SuppressWarnings("deprecation")
    public static void main(String a[]){         
        Deprecate test = new Deprecate();
        test.showDM();
    }
}

Some notes on @SuppressWarnings:
1. Undefined or vague warnings have no effect.
2. Once a programs element is annotated by a @SuppressWarning, all of its sub-elements/components are also affected.

1.5 @FunctionalInterface:

The major advantage to safeguard your interface by @functionalInterface is once you use lambda to instantiate them. The functional interface will have just only one abstract method. If you have got two abstract methods then your interface isn’t any longer functional. It is not at all necessary to use them, however, it is a good practice to use it with functional interfaces to avoid accidental addition of extra methods. The foremost advantage of java 8 functional interfaces is that we are able to use lambda expressions to instantiate them and avoid using large and bulky anonymous class implementation.

2. Meta Annotations:

A meta-annotation is just an annotation, which can be applied to another annotation. They can also be combined together to create composed annotations. For instance, the @RestController annotation from Spring MVC is made of @Controller and @ResponseBody.

Java has included some important meta-annotations directly in the language specification.

2.1 @Retention:

It clearly states how long the annotation should be retained by the compiler as there is no reason for a compiler annotation to be present at runtime. The order from shortest to longest retention, are:

RetentionPolicy.SOURCE
RetentionPolicy.CLASS
RetentionPolicy.RUNTIME

2.2 @Documented:

It states that if the Annotation itself is annotated by @Documented, then in the java documentation, the annotation will also be shown with the description of class and members.
For Example:

import java.lang.annotation.Documented;
@Documented
@interface One{}
@interface Two{}
@Two
@One
public class Example{}

When the documentation for the class Example is made then @One will be shown in the document and @Two will not.

2.3 @Target:

It describes the targets to which an annotation can be applied. In easier words, we are able to conjointly say that the @Target meta-annotation determines what could also be marked by the annotation. If the @Target is method and annotation is applied on the other element lets imagine class, then the compiler will generate an error.

2.4 @Inherited:

It denotes that annotation should be inherited by a subtype if applied to a supertype.
For Example:

@Inherited
@interface Universal { }
@interface Not_Universal { }
@Universal
@Not_Universal
class Parent_Class { }
class Child_Class extends Parent_Class { }

In this example, Parent_Class is annotated with @Universal and @Not_Universal. And Child_Class is not marked with any. Child_Class inherits @Universal because it is annotated with @Inherited. @Not_Universal is not annotated, so it isn’t inherited by Parent_Class.

2.4 @Repeatable:

A @Repeatable annotation type is repeatable – i.e. can be specified multiple times on the same class. Look here more on relatable annotations

3. Custom Annotations:

Java Custom annotations or Java User-defined annotations are easy to create and use. To declare the annotation we use the @interface element. We can create them simply by @interface MyCustomAnnotation{}. Here MyCustomAnnotation is the name of the Annotation.
There are three types of annotations.

3.1 Marker Annotation:

An annotation that has no method, is called marker annotation. The @Override and @Deprecated are marker annotations.

@interface CustomMarkerAnnotation{}

ii). Single-Value Annotation: An annotation that has one method, you can pass single value.

@interface CustomSingleValueAnnotation{
int value();
}

iii). Multi-Value Annotation: An annotation that has more than one method, you can pass multiple values.

@interface CustomMultiValueAnnotation{
int v1();
String v2();
String v3();
}

Points to be noted:
1. The method should not have any throws clauses.
2. The method should return either primitive data types, enum or array of these data types, String, Class,.
3. The method should not be having any parameters.
4. It may assign a default value to the method.

Example on how to declare the annotation Example without any value

public @interface Example {
}
@Example
public void toggle() {
}

Conclusion

Java annotations are a very powerful feature in the Java language, but most often, we are the users of standard annotations or common framework annotations rather than their developers.

References:

Happy Learning 🙂