Recent Posts

Tuesday, 5 June 2018

Java Annotations Tutorial

Java Annotations
1. Annotations are introduced in java 5.0.
2. Annotations allow us to provide metadata (data about data) information into our source code.
3. In java all annotations are interfaces only. 
4. Already in Java to provide metadata already we have comments right? then what is the need of Java Annotations?
     In any programming language, compilation is work from following 4 machines 
1. Pre-Processor
2. Compiler
3. Assembler
4. Loader / Link editor
     In Java compilation phase pre-processor is not existed. Because in java #include statements are not available. 
     Compiler phase existed 6 number of phases.

1. Lexical Analyzer
     Lexical analyzer phase is the first phase of compilation process. It takes source code as input. It reads the program and converts it into tokens. It converts a stream of lexemes into a stream of tokens. Tokens are defined by regular expressions which are understood by the lexical analyzer. It also removes white-spaces and comments.

2. Syntax Analysis
     Syntax analysis is the second phase of compilation process. It takes tokens as input and generates a parse tree as output. In syntax analysis phase, the parser checks that the expression made by the tokens is syntactically correct or not.

3. Semantic Analysis
     Semantic analysis is the third phase of compilation process. It checks whether the parse tree follows the rules of language. Semantic analyzer keeps track of identifiers, their types and expressions. The output of semantic analysis phase is the annotated tree syntax.

4. Intermediate Code Generation
     In the intermediate code generation, compiler generates the source code into the intermediate code. Intermediate code is generated between the high-level language and the machine language. The intermediate code should be generated in such a way that you can easily translate it into the target machine code.

5. Code Optimization
     Code optimization is an optional phase. It is used to improve the intermediate code so that the output of the program could run faster and take less space. Optimization can be assumed as something that removes unnecessary code lines and arranges the sequence of statements in order to speed up the program execution without wasting resources (CPU, memory). 

6. Code Generation
     Code generation is the final stage of the compilation process. It takes the optimized intermediate code as input and maps it to the target machine language. Code generator translates the intermediate code into the machine code of the specified computer.
     So, in lexical analysis phase the specified complete meta data in the form of comments would be removed from our source program. 
     If you open the .class file then meta data is not available. But my requirement is I want bring my meta data to up to .java file, up to .class file and up to runtime (to debug or test our application). So, if you want test or debug your application then comments are not sufficient. So, we must go for annotations.

Annotations Declaration Syntax
@interface AnnotationName { 
   members
} 
Members syntax
datatype memberName() [default value] 
Annotations Utilization Syntax
     In java annotations are applicable for variables, methods, constructors, interfaces, another annotation, enum and classes. 
Syntax 
@AnnotationName (member1 = value1, member2 = value2,…...)
     Based on annotation members, annotations are divided in to 3 types.
1. Marker Annotation
2. Single valued Annotation
3. Mutli valued Annotation

1. Marker Annotation
     A marker annotation is a special type of annotation which contains no members.
E.g: @Override

2. Single valued Annotation
    Single valued annotation is the annotation which contains only one member.    
E.g: @SupressWarnings("unchecked")

3. Mutli valued Annotation
    Multi valued annotation is the annotation which contains more than one member.    
E.g: @WebServlet(
        name = "MyServlet",
        description = "This is my first annotated servlet",
        urlPatterns = "/processServlet"
        )

Classifications of Annotations
     In java, Annotations are divided into 2 types.
1. Standard Annotations
2. Custom Annotations

1. Standard Annotations
     Standard annotations are the annotations which are provided by Java. Standard annotations are divided in to 2 types
1. General purpose annotations.
2. 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.
1. @Override
2. @SupressWarnings
3. @Deprecated
4. @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:
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.
E.g @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.
1. @Inherited
2. @Documented
3. @Target
4. @Retention

1. @Inherited
     By default, Java annotations are not inheritable from super class to sub class. For example,
@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. 
@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 anotation 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 documentable. For example
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; 
@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.
1. Annotation with retention policy SOURCE will be retained only with source code and discarded during compile time.
2. Annotation with retention policy CLASS will be retained till compiling the code and discarded during runtime.
3. Annotation with retention policy RUNTIME will be available to the JVM through runtime.
4. The default retention policy type is CLASS. 
@Retention(RetentionPolicy.RUNTIME) 
public @interface MyAnnotation { 
    String name (); 
    String desc (); 
} 

class MyAnnTest{ 
    @MyAnnotation (name = "test", desc = "testing annotations") 
    public void myTestMethod(){ 
        //method implementation 
    } 
}
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
1. Define user defined annotation
2. Utilize user defined annotation
3. Access data from user defined annotation

1. Define user defined annotation  
import java.lang.annotation.*; 
@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
@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.*; 
public class AnnotationTest { 
   public static void main (String args[]) { 
      Student s = new Student ("Ashok", "E0087", "Bhimavaram"); 
      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 it guys. This is all about Java Annotations Tutorial. Let me know your comments and suggestions about this tutorial. Thank you.

No comments:

Post a Comment