Classifications of Annotations
In this tutorial, we are going to discuss about Classifications of Annotations. Annotations in Java can be classified based on their usage, purpose, and retention policy.
In java, Annotations are divided into 2 types.
- Standard Annotations
- Custom Annotations
1. Standard Annotations
Standard annotations are the annotations which are provided by Java. Standard annotations are divided in to 2 types
- General purpose annotations.
- Meta annotations.
1. General purpose annotations
General purpose annotations are the annotations which are used for normal purpose. General purpose annotations are available in java.lang package.
- @Override
- @SupressWarnings
- @Deprecated
- @FunctionalInterface (Introduced in Java 8)
1. @Override
@Override annotation is used when we override a method in sub class.
class Parent {
public void display (String msg) {
System.out.println(msg);
}
}
class Child extends Parent {
@Override
public void display (String msg) {
System.out.println("Message is: "+ msg);
}
public static void main (String args[]) {
Child ch = new Child ();
ch.display("Hi This is Ashok...!!");
}
}
In the above example we are overriding a method display() in the child class. Even if we don’t use the @Override annotation, the program would still run fine without any issues, you would be wondering the why do we use this annotation at all. Let’s discuss about it.
1) If programmer makes any mistake such as wrong method name, wrong parameter types while overriding, you would get a compile time error. As by using this annotation you instruct compiler that you are overriding this method. If you don’t use the annotation then the sub class method would behave as a new method (not the overriding method) in sub class.
2) It improves the readability of the code. So, if you change the signature of overridden method then all the sub classes that overrides the particular method would throw a compilation error, which would eventually help you to change the signature in the sub classes. If you have lots of classes in your application then this annotation would really help you to identify the classes that require changes when you change the signature of a method.
2. @SupressWarnings
The @SuppressWarnings annotation allows us to disable compilation warnings for a certain part of a program (type, field, method, parameter, constructor, and local variable). Normally warnings are good. However, in some cases they would be inappropriate and annoying. So, programmers can choose to tell the compiler ignoring such warnings if needed.
This annotation type must be used with one or more warnings as its arguments, for example:
@SuppressWarnings("unchecked")
@SuppressWarnings({"unchecked", "deprecation"})
List of warnings vary among Java compilers. The Java Language Specification mentions only “unchecked” warning. To see the list of warnings which would be issued by the Oracle’s Java compiler, type the following command:
javac -X
Warnings issued by Oracle’s Java compiler are: all, cast, classfile, deprecation, dep-ann, divzero, empty, fallthrough, finally, options, overrides, path, processing, rawtypes, serial, static, try, unchecked, varargs.
Different IDEs provide different list of warnings issued by their own compilers, e.g. list of suppress warnings provided by Eclipse IDE’s Java compiler.
- all to suppress all warnings
- boxing to suppress warnings relative to boxing/unboxing operations
- cast to suppress warnings relative to cast operations
- dep-ann to suppress warnings relative to deprecated annotation
- deprecation to suppress warnings relative to deprecation
- fallthrough to suppress warnings relative to missing breaks in switch statements
- finally to suppress warnings relative to finally block that don’t return
- hiding to suppress warnings relative to locals that hide variable
- incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)
- javadoc to suppress warnings relative to javadoc warnings
- nls to suppress warnings relative to non-nls string literals
- null to suppress warnings relative to null analysis
- rawtypes to suppress warnings relative to usage of raw types
- resource to suppress warnings relative to usage of resources of type Closeable
- restriction to suppress warnings relative to usage of discouraged or forbidden references
- serial to suppress warnings relative to missing serialVersionUID field for a serializable class
- static-access to suppress warnings relative to incorrect static access
- static-method to suppress warnings relative to methods that could be declared as static
- super to suppress warnings relative to overriding a method without super invocations
- synthetic-access to suppress warnings relative to unoptimized access from inner classes
- sync-override to suppress warnings because of missing synchronize when overriding a synchronized method
- unchecked to suppress warnings relative to unchecked operations
- unqualified-field-access to suppress warnings relative to field access unqualified
- unused to suppress warnings relative to unused code and dead code
Suppressing warnings on using unchecked generic types operations:
@SuppressWarnings("unchecked")
void uncheckedGenerics() {
List nameList = new ArrayList();
nameList.add("Ashok"); // this causes unchecked warning
}
Note
1. Undefined warnings have no effect,
E.g
@SuppressWarnings(“blahblah”). The compiler will ignore that silently.
2. When a program’s element is annotated by the @SuppressWarnings, all of its sub elements are also affected. For example, if you suppress a warning at class level, then all code inside that class is also applied.
3. @Deprecated
@Deprecated annotation is used for informing compiler that the particular method, class or field is deprecated and it should generate a warning when someone try to use any of the them.
To deprecate a method, class or field by using @Deprecated annotation and we use @deprecated Javadoc tag in the comment section to inform the developer, the reason of deprecation and what can be used in place of this deprecated method, class or field. For example:
import java.lang.annotation.*;
/**
*
* @author ashok.mariyala
*
*/
public class MyDeprecated {
/**
* @deprecated
* reason for why it was deprecated
*/
@Deprecated
public void showMessage(){
System.out.println("This method is marked as deprecated");
}
public static void main (String args[]){
MyDeprecated md = new MyDeprecated();
md.showMessage();
}
}
4. @FunctionalInterface
Java 8 introduces functional interfaces. If an interface has only one abstract method, then it is known as the functional interface. This can be annotated with @FunctionalInterface annotation.
Note
1. Functional interface has only one abstract method
2. @FunctionalInterface annotation can be used for denoting the functional interface. However, it is not necessary to use this annotation, it is only useful to catch the error in the compile time. When you annotate an interface with @FunctionalInterface, if more than one abstract method is defined it will throw a compiler error.
3. Functional interfaces can define one or more default methods.
@FunctionalInterface
public interface MyFuncInterface {
public void getValue();
}
2. Meta annotations
Meta annotations are annotations about annotations. To prepare annotations we are going to use meta annotations. Meta annotations are available in java.lang.annotation package.
- @Inherited
- @Documented
- @Target
- @Retention
1. @Inherited
By default, Java annotations are not inheritable from super class to sub class. For example,
import java.lang.annotation.*;
@interface Persistable {
------------------------
------------------------
}
@Persistable
class Employee {
String empId;
String empName;
String salary;
}
class Manager extends Employee {
public getManagerDeatils() {
System.out.println(empId);
System.out.println(empName);
System.out.println(salary);
}
}
Here we are applying annotation for only super class. Here Manager class is not Persistable even though inheritance concept is available, why because by default annotations are not inheritable. But when you declare Persistable annotation as @Inherited annotation then @Persistable annotation is becoming as inheritable from super class to sub class.
import java.lang.annotation.*;
@Inherited
@interface Persistable {
------------------------
------------------------
}
@Persistable
class Employee {
String empId;
String empName;
String salary;
}
class Manager extends Employee {
public getManagerDeatils() {
System.out.println(empId);
System.out.println(empName);
System.out.println(salary);
}
}
Now both Employee and Manager classes are persistable. If we remove @Inherited annotation then only Employee class is persistable and Manager class is not persistable.
So, the main purpose of @Inherited annotation is to make any annotation as inheritable from super class to child classes.
2. @Documented
By default in Java annotations are not document-able. For example
/**
*
* @author ashok.mariyala
*
*/
public class Employee {
String empId;
String empName;
String salary;
Employee (String empId) {
this.empId = empId;
}
Employee (String empId, String empName) {
this.empId = empId;
this.empName = empName;
}
Employee (String empId, String empName, String salary) {
this.empId = empId;
this.empName = empId;
this.salary = salary;
}
Public void getEmployeeDetails() {
System.out.println(empId);
System.out.println(empName);
System.out.println(salary);
}
}
If we prepare documentation for above employee class using javadoc tool then we are able to see all fields information, constructor’s information and methods information inside our html documentation. But if you add @Persistable annotation in Employee class then this annotation is not documented inside our html documentation. If you want to see @Persistable annotation in documentation then we must declare @Documented in @Persistable
@Documented
@interface Persistable {
------------------------
------------------------
}
3. @Target
The main purpose of @Target annotation is to define to which set of programming elements that we want apply the annotation. That means in Java programming we can apply annotations for variables, methods, classes, constructors, packages, local variables and another annotation. We can apply annotations for all the programming elements.
Syntax
@Target(ElementType value)
Here ElementType is the enum which contains following values.
Target Constant Annotations Can be Applied To
----------------- ---------------------------------
ANNOTATION_TYPE Another annotation
CONSTRUCTOR Constructor
FIELD Field
LOCAL_VARIABLE Local variable
METHOD Method
PACKAGE Package
PARAMETER Parameter
TYPE Class, Interface, or enumeration
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
/**
*
* @author ashok.mariyala
*
*/
@Target({ElementType.METHOD})
public @interface MyAnnotation {
String value();
}
The above example shows a Java annotation that can only be used to annotate methods.
4. @Retention
@Retention annotation sets the visibility of the annotation to which it is applied. Java defined 3 types of retention policies through java.lang.annotation.RetentionPolicy enumeration. It has SOURCE, CLASS and RUNTIME.
- Annotation with retention policy SOURCE will be retained only with source code and discarded during compile time.
- Annotation with retention policy CLASS will be retained till compiling the code and discarded during runtime.
- Annotation with retention policy RUNTIME will be available to the JVM through runtime.
- The default retention policy type is CLASS.
import java.lang.annotation.*;
/**
*
* @author ashok.mariyala
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String name ();
String desc ();
}
class MyAnnTest{
@MyAnnotation (name = "test", desc = "testing annotations")
public void myTestMethod(){
//method implementation
}
}
2. Custom annotations
Custom annotations are defined by the developers as per the application requirements. If you want define user defined annotations in java we need following steps
- Define user defined annotation
- Utilize user defined annotation
- Access data from user defined annotation
1. Define user defined annotation
import java.lang.annotation.*;
/**
*
* @author ashok.mariyala
*
*/
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Course {
String courseId default "123";
String courseName default "Java";
String price default 5000;
}
2. Utilize user defined annotation
/**
*
* @author ashok.mariyala
*
*/
@Course(courseId = "1234", courseName ="C++", price = 2500)
public class Student {
String name;
String id;
String address;
public Student (String name, String id, String address) {
this.name = name;
this.id = id;
this.address = address;
}
public void getStudentDetails() {
System.out.println("Student Name is : " +name);
System.out.println("Student Id is : " +id);
System.out.println("Student address is : " +address);
}
}
3. Access data from user defined annotation
import java.lang.annotation.*;
/**
*
* @author ashok.mariyala
*
*/
public class AnnotationTest {
public static void main (String args[]) {
Student s = new Student ("Ashok", "E0087", "Hyderabad");
s.getStudentDetails();
Class clazz = Student.class;
Annotation ann = clazz.getAnnotation(Course.class);
Course c = (Course) ann;
System.out.println("Course Id: " +c.courseId ());
System.out.println("Course Name: " +c.courseName ());
System.out.println("Course Price: " +c.price());
}
}
That’s all about the Classifications of Annotations in java. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Java.!!